Metadata-Version: 2.4
Name: jaato-server
Version: 0.9.0
Summary: Jaato Server - LLM tool orchestration runtime and daemon
Author: apanoia
License-Expression: BUSL-1.1
Project-URL: Repository, https://github.com/Jaato-framework-and-examples/jaato
Project-URL: Issues, https://github.com/Jaato-framework-and-examples/jaato/issues
Keywords: llm,ai,tools,orchestration,vertex-ai,gemini
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: jaato-sdk
Requires-Dist: requests
Requires-Dist: mcp[cli]
Requires-Dist: google-api-core
Requires-Dist: certifi
Requires-Dist: python-dotenv
Requires-Dist: pyreadline3; sys_platform == "win32"
Requires-Dist: pyyaml
Requires-Dist: websockets>=12.0
Requires-Dist: anthropic>=0.40.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: psutil>=5.0.0
Requires-Dist: watchdog>=4.0.0
Requires-Dist: rich>=13.0.0
Requires-Dist: wcwidth
Requires-Dist: jsonschema>=4.0.0
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-asyncio; extra == "dev"
Requires-Dist: radon; extra == "dev"
Provides-Extra: google
Requires-Dist: google-genai; extra == "google"
Requires-Dist: google-auth; extra == "google"
Provides-Extra: github-models
Requires-Dist: azure-ai-inference>=1.0.0b7; extra == "github-models"
Provides-Extra: nim
Requires-Dist: openai>=1.0; extra == "nim"
Provides-Extra: openai
Requires-Dist: openai>=1.66; extra == "openai"
Provides-Extra: azure-openai
Requires-Dist: openai>=1.66; extra == "azure-openai"
Requires-Dist: azure-identity>=1.15.0; extra == "azure-openai"
Provides-Extra: openrouter
Requires-Dist: openai>=1.0; extra == "openrouter"
Provides-Extra: ovhcloud
Requires-Dist: openai>=1.0; extra == "ovhcloud"
Provides-Extra: web
Requires-Dist: trafilatura>=1.6.0; extra == "web"
Requires-Dist: html2text>=2024.2.26; extra == "web"
Requires-Dist: beautifulsoup4>=4.12.0; extra == "web"
Requires-Dist: lxml>=5.0.0; extra == "web"
Requires-Dist: pymupdf4llm>=0.2.0; extra == "web"
Requires-Dist: ddgs>=7.0.0; extra == "web"
Provides-Extra: interactive
Requires-Dist: pexpect>=4.8.0; sys_platform != "win32" and extra == "interactive"
Requires-Dist: wexpect>=4.0.0; sys_platform == "win32" and extra == "interactive"
Requires-Dist: pywin32>=220; sys_platform == "win32" and extra == "interactive"
Requires-Dist: setuptools; sys_platform == "win32" and extra == "interactive"
Provides-Extra: ast
Requires-Dist: ast-grep-py>=0.30.0; extra == "ast"
Provides-Extra: notebook
Requires-Dist: ipython-pygments-lexers>=1.0.0; extra == "notebook"
Provides-Extra: diagrams
Requires-Dist: Pillow>=10.0.0; extra == "diagrams"
Provides-Extra: templates
Requires-Dist: pybars3>=0.9.7; extra == "templates"
Requires-Dist: Jinja2>=3.1.0; extra == "templates"
Provides-Extra: kaggle
Requires-Dist: kaggle>=1.5.0; extra == "kaggle"
Provides-Extra: kerberos
Requires-Dist: pyspnego[kerberos]>=0.10.0; extra == "kerberos"
Provides-Extra: telemetry
Requires-Dist: opentelemetry-api>=1.20.0; extra == "telemetry"
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == "telemetry"
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.20.0; extra == "telemetry"
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.20.0; extra == "telemetry"
Provides-Extra: all
Requires-Dist: jaato-server[ast,azure-openai,dev,diagrams,github-models,google,interactive,kaggle,kerberos,nim,notebook,openai,openrouter,ovhcloud,telemetry,templates,web]; extra == "all"

# Changelog

## 0.9.0 (2026-09-10)

- fix(scaffold): validate a knob's VALUE, not only its name (#925) (#935)
- fix(session): spend the completion-nudge budget per turn, not per session (#934) (#936)
- fix(plugins): make out-of-tree plugin authoring safe (#917, #918) (#933)
- feat(webhook): secret_algo "token" for plain shared-secret headers (#930) (#932)
- feat(spawn-schema): ratify spawn_payload_schema as a string-shaped boundary (#883) (#931)
- feat(profiles): max_completion_nudges — the nudge budget is the deployment's (#919) (#927)
- fix(enrichment): every dict tool result reaches the enrichment chain (#922) (#924)
- fix(runner-rpc): serialise bytes as base64, not as a Python repr (#920) (#921)
- fix(session): record signal_completion's tool result so a completed session stays revivable (#913) (#915)
- fix: satisfy the two contract guards this branch broke
- feat(resume): both resume verbs carry an attachment (#845) (#914)
- feat(providers): native OpenAI (Chat Completions + Responses API) and Azure OpenAI (#907)
- skill: state the `plugins: []` case outright — the wrong rule is in circulation
- scaffold: make `--user` real — the listing promised a flag the parser rejected
- scaffold: `integration`, not `install` — jaato's side of a contract with a tool
- scaffold: `dependencies` as a facet of any explain scope, and a doctor check
- feat(providers): MiniMax, Kimi and MiMo providers, and the reasoning-replay seam they need (#875)
- scaffold: `install` verb — ship the skill with the framework, stamp every copy
- template: make output-path routing a profile knob (#900) (#903)
- runner pool: a reservation is not capacity (#898) (#901)
- explain paths: state that config_root is framework-owned (#896) (#897)
- fix(apparmor,template): deny writes to .jaato/templates/ under confinement (#893) (#894)
- feat(runtime_limits): expose tool concurrency as max_parallel_tools (#862)
- feat(web): replace the web-client PoC with jaato-web, a browser client on @jaato/sdk
- fix(sdk,scaffold,lsp): four defects found building a cascade harness on the SDK (#879)
- fix(runner): carry slot-scoped plugin instances across cascade sessions (#890) (#891)
- fix(service_connector): mark call_service results untrusted (#857) (#878)
- feat(permission): the resolved event, the ledger and the session record name who decided (#859) (#876)
- fix(trace): record the resolved tool name beside the hashed wire id (#873) (#874)
- feat(security): scrub secret env vars from model-driven subprocesses by default (#863) (#872)
- fix(media): the spoken transcript rides the final media chunk to the client (#869) (#871)
- docs: AppArmor is not premium, the licence is not MIT, image input is not 4 of 13 providers (#866) (#870)
- fix(gc): evict consumed inbound media, and let GC see media at all (#850) (#853)
- feat(scaffold): the sweep gate as one set, and make its ceiling actually work (#768 #769 #770 #772) (#849)
- fix(session): history replay is gated by what the ACTIVE model can consume (#847) (#848)
- fix(scaffold): the templates take their turn from the SDK facade (#820 #821 #825 #826 #827 #822)
- fix(web_search): file the tool under `web`, the category that advertises it (#843) (#844)
- fix(daemon): an attachment is content, so a message carrying one is not empty (#838) (#841)
- fix(session): an attachment in the message no longer means "do not stream" (#837) (#840)
- feat(tiers): let a deployment NAME its own tiers (#831) (#839)
- feat(providers): give the framework ears — audio input reaches a model (#830) (#835)
- fix(providers): dispatch inbound attachments on mime instead of assuming image (#829) (#833)
- feat(tiers): a tier that exits on completion, and a final flag that comes from the wire (#828)
- feat(media): deliver binary media chunks, and know when a spoken turn ended (#824)
- feat(tiers): per-tier description + direction-qualified modality roles (#818)
- fix(tests): stop credential tests reading the developer's machine, and printing the key (#721, #734) (#817)
- fix(introspection): make an unknown category_id recoverable in one round-trip (#754) (#816)
- fix(file_edit): name the failure, not just the remedy, on edit errors (#813, #814) (#815)
- fix(sandbox): allow POSIX pseudo-devices, so 2>/dev/null works (#784) (#811)
- fix(background): don't issue a task_id no tool in the session can read (#810)
- fix(file_edit): preserve line endings, honouring the repo's setting (#805) (#809)
- feat(app-identity): let an application name itself, not report as jaato (#808)
- chore: normalise line endings to LF, once, in one commit (#794) (#807)
- feat(events): carry the billed prompt/output split on the wire (#802) (#803)
- fix(tui,permission): make a permission prompt readable, and answerable only as chosen (#796)
- feat(session): a revive wakes from persisted state, not from disk (#787) (#795)
- feat(env): tag every env var with its scope and promote the trace paths (#775) (#793)
- fix(profiles): a child can decline one inherited completion processor (#791) (#792)
- fix(file_edit): reject updateFile with no content instead of truncating (#782) (#788)
- fix(providers): a stream that dies mid-response is not a finished turn (#687) (#786)
- feat(scaffold): explain the user-facing command surface (#715) (#785)
- fix(tui,clarification): answer a batched clarification instead of hanging (#704) (#783)
- fix(openrouter): a bare finish_reason="error" names its cause and retries (#766) (#780)
- fix(plugins): reserve built-in plugin names against entry-point shadowing (#684) (#779)
- fix(egress): loopback is reachable only at the proxy's address:port (#696) (#778)
- fix(sdk,session): a turn boundary is not the session's terminus (#767) (#774)
- fix(providers): one prompt-token convention, converted at the seam (#758) (#763)
- fix(session): a turn cut off at the output cap must be continued, not lost (#749) (#759)
- docs(scaffold): name the profile env: block where authors look (#752) (#760)
- fix(session): a call the severed turn never ran must still be answered (#751) (#757)
- fix(providers): unreadable tool-call arguments must not become a call (#750) (#753)
- fix(providers): a truncated turn must not report as a tool-use turn (#745) (#747)
- fix(security): close the symlink escapes in file tools and search (#669) (#746)
- fix(daemon): refuse a relative path at the process boundary (#742) (#744)
- fix(openrouter): bound a single request with an idle deadline (#732) (#743)
- perf(ci): memoize the whole-tree env scan and fan the suites out (~11min -> ~4min) (#740)
- fix(cache): model tiers × prompt caching — the knobs never arrived, and the cost was invisible (#737)
- fix(cli): segment compound commands in the permission analyzer (#668) (#739)
- docs(scaffold): document what `new` produces (#738)
- feat(openrouter): put the session id on the wire so a conversation groups (#733)
- fix(openrouter): read the Retry-After hint OpenRouter puts in the body (#720)
- feat(prompt): narrate tool calls as they happen, and give batching a decision rule (#711)
- fix(providers): rebuild the HTTP client after a connection error (#709)
- feat(plugins): declare the session-persistence contract, and use it for permissions (#708)
- fix(session): a profile-less session got no tools, and the enabling tool was documented as a lookup (#703)
- fix(pool): the pre-warm pool had a floor and no ceiling (#667)
- fix(events): the 64-call-site emit path now says which session it is about (#666)
- test(guards): a guard that cannot detect its own reversion now fails the build (#665)
- fix(memory): list_memory_tags reported an empty store while holding a raw queue (#664)
- fix(scaffold): a sweep job that could not do its work is not a result (#662)
- docs(subagent): the prefetch README documented the behaviour that caused fabrication
- feat(daemon): separate the threads that are blocked from the one that is blocking (#659)
- fix(ci): the complexity ratchet measured build artifacts, so it was green only on CI (#658)
- fix(daemon): the manager lock was held across a round-trip to the loop (#657)
- ci: cyclomatic-complexity ratchet, fixed so it cannot silently skip (#656)
- feat(daemon): a stalled loop now names the thread that HELD it, not just the one that waited (#655)
- feat(events): a stage that was asked twice to signal completion, and never did, says so (#654)
- test(guards): a lazily-discovered cache must never be observable half-built (#653)
- fix(secrets): the resolver registry was published EMPTY before it was filled (#652)
- fix(scaffold): every template now tracks the SDK contract it was written for (#650)
- feat(scaffold): a `sweep` archetype for N independent arms (#649)
- fix(runner): a reused pool slot no longer carries the previous session's env (#647)
- fix(history): a history request is answered or refused, never met with silence (#645)
- fix(usage): a provider-reported cost now reaches TurnCompletedEvent (#644)
- fix(session): a terminal event is now the last thing a session emits (#643)
- fix(cascade): an exhausted pool no longer hands back a working-looking handle (#642)
- feat(echo): a provider that costs nothing can still REPORT a spend (#641)
- feat(sdk): one pairing rule, in the layer consumers can import (#640)
- fix(history): the call side carried no identifier, so nothing could be paired (#639)
- fix(daemon): the last silent cache writer, and a property that lied (#638)
- fix(daemon): the context-limit heal path now says what it did (#637)
- fix(delivery): unreachable was five outcomes wearing one word (#634)
- fix(daemon): the loop can no longer deadlock on itself (#633)
- fix(memory): a usage write-back can no longer undo a curator's decision (#632)
- feat(daemon): a stalled event loop now names what it was doing (#631)
- fix(memory): reading the raw queue no longer empties it (#630)
- fix(lifecycle): the transport branch now actually exits — #628 fell through (#629)
- fix: three things that told a caller something false (#628)
- fix(observability): make two shipped fixes readable — #623's witness, and what the outer timeout means (#627)
- fix(session): saves of one session serialize; unrelated sessions do not (#626)
- fix(rpc): a stacked timeout now says WHICH of the two fired (#625)
- feat(runner): give the control plane its own lane (#624)
- fix(delivery): the wind-down stash was a slot, not a queue — #620 regression (#623)
- fix(delivery): make `unreachable` say why — and not render a timeout blank (#622)
- docs(delivery): retire the queued caveat that #620 fixed (#621)
- fix(delivery): the session decides whether a turn will drain your message (#620)
- fix(inject): an inject into an idle session was a black hole, and said "ok" (#619)
- diag(sibling): log the busy decision — stale flag and mid-turn look identical (#618)
- fix(cascade): a message queued to a busy peer that went idle was stranded (#617)
- feat: cascade refusals reach observers; explain reports inherited instruction cost (#611)
- feat(scaffold): explain plugin publishes tool PARAMETERS (#615)
- fix(session): an orphaned fragment crashed EVERY drain that had a callback (#616)
- fix(diagnostics): model-loop frames were discarded before an ErrorPayload existed (#614)
- fix(diagnostics): runner-side tracebacks never reached any consumer (#613)
- refactor(delivery): one queue-or-drive decision for every message sender (#612)
- fix(sibling): a cold sibling reported no_such_sibling, not sibling_cold (#610)
- fix(session): attach lost a session its daemon-side plugin wiring (#609)
- fix(executor): two 2-tuple conventions shared one representation (#608)
- feat(session): session.send — nudge a NAMED session without the model (#607)
- feat(subagent): send_to_sibling — cascade messaging with a receipt (#606)
- fix(history): request_history sent tool results as a Python repr, not data (#605)
- fix(security): the untrusted-content mark must survive every ToolResult rebuild (#604)
- feat(protocol): every event says which session it is about (#603)
- fix(rpc): a forwarded executor's (ok, payload) contract must survive the wire (#602)
- fix(plugins): migrate status-error results to the key the checker reads (#601)
- fix(subagent): list_siblings never forwarded — the registry hook was missing (#600)
- feat(subagent): list_siblings — the cascade roster (#599)
- feat(protocol): correlate session.new with the event that answers it (#598)
- fix(session): a sibling-name refusal must reach the client (#596)
- docs(scaffold): there is no jaato.premium_reactors entry-point group (#595)
- fix(session): cascade membership must survive a reload (#594)
- fix(sdk): sibling_name reaches the facade — and peer→sibling for the coordination surface (#593)
- feat(session): peer_name — a cascade-scoped address validated at session.new (#592)
- fix(scaffold): `new` must not blame itself for USER-tier profile errors (#591)
- feat(queue): SourceType.PEER, idle-only, and tier membership declared once (#590)
- fix(permission): gate parent-authority answers on the stamped sender, not content (#589)
- feat(budget): create-time budget_control + budget_usage params (#588)
- feat(gc): typed GC lifecycle events on the bus (#587)
- refactor(gc): route every GC pass through one instrumented path (#586)
- fix(budget): surface a ceiling refusal as a terminal, typed event (#584)
- fix(budget): carry the CEILING across a reload, and stop destroying the snapshot (#583)
- A ceiling that fired before a suspend still refuses after the resume
- budget_usage never reached disk: the serializer writes a fixed key list
- Wire budget usage through save/restore so the ceiling actually survives
- Drop a wall-clock floor that measured the runner, not the handshake
- budget_control: usage survives a reload, and an abort has a typed signal
- HOTFIX: bound_model_for_profile was not bound at module scope (#576 broke all profile sessions)
- Tiers-only profiles: fix the remaining producers; make completion latches per-turn
- One definition of "the model a profile binds" (fixes two #574 follow-ons)
- A tiers-only profile can bootstrap a session
- feat(telemetry): include the system prompt in OpenInference input spans
- notebook analyzer: report bare dangerous attributes, anchor relative paths (closes the last 2 xfails)
- disable_colors() now suppresses syntax highlighting too (closes 2 xfails)
- Surface a backgrounded tool's return value on the poll (closes 4 xfails)
- Declare Jinja2 in the `templates` extra (CI could not run the template tests)
- Repair the final shared/plugins failures (0 failing, 8 recorded gaps)
- Repair todo/memory/lsp tests; record the disable_colors gap
- Repair shared/plugins/tests (was 4 failing)
- Repair model_provider tests + stop them reading real credentials
- Fix the webhook -> EventBus bridge: capture the bus at subscribe time
- Record: the webhook -> EventBus bridge never publishes
- Repair references merge tests (375 passing; was 5 failing)
- Fix UnboundLocalError that broke inline mermaid rendering
- Repair filesystem_query tests (was 9 failing)
- Repair subagent tests (373 passing; was 13 failing)
- Fix privilege escalation: askPermission granted the whole tool, not the call
- Repair permission tests + record a privilege-escalation defect
- Repair background tests + record a real capability gap (89 pass, 4 xfail)
- Repair file_edit tests (292 passing; was 8 failed + 20 errors)
- Repair 59 stale test doubles in server/tests (0 failing, was 59)
- Make the truthy-but-empty exception mistake hard to write
- Fix the empty () in the push-timeout log; record that the bound is conservative
- cascade.budget.get states its scope in the payload
- Degrade steps apply at most once and in order, per ladder not per tracker
- Budget origin labels now name the MECHANISM, not whose ladder
- Separate budgets: a child that declared one is not clamped by the parent
- Isolated subagent spawns dropped the profile's declared budget
- Subagents never received their own declared budget
- A profileless cascade child inherits the cascade's degrade ladder
- A push timeout means DELAYED, not lost — and the log said otherwise
- scaffold: add --secrets flag; default profiles to env-var credentials
- Cascade degrade notices must be emitted by the daemon, not the session
- Fix: the degrade-push dispatch read a field that does not exist
- Fix: the cascade degrade push blocked the whole SessionManager
- Fix: concurrent create_session issued DUPLICATE session ids
- Slice 3: push a crossed cascade rung to already-running children
- test: pin the cascade observer/attached-client dedup
- Cascade refusal must reach the client, not just the daemon log
- Cascade pool: reconcile against the session tracker, not the event stream
- Fix: a CANCELLED turn's spend reached no TurnCompletedEvent
- IPC verbs for cascade budgets: set / get / clear
- Slice 2: cascade budgets wired — declare, accumulate, clamp at spawn
- Thread spend_total_tokens to the client (UsageBreakdown)
- Fix: spend_* was accumulating on the streaming path only
- Separate per-turn SPEND from end-of-turn context size
- CascadeExhaustedError carries framework-generated evidence
- Add CascadeBudgetPool: the aggregate cascade ceiling (design note §8/b)
- Budget: a refused turn must not emit TurnCompletedEvent
- Budget: enforce the ceiling past the first abort; surface to the client
- Fix: envelope producer never populated budget_control (feature was dead)
- Implement budget_control runtime layer: tracker + brownout degradation
- Implement budget_control config + scaffold discoverability
- telemetry: set_llm_span_attributes hook (prompt→trace linking) + fix flaky budget-gate tests
- feat(session): pre-flight refuse-send gate (PayloadExceedsContextError)
- telemetry: emit user.id for Langfuse User Tracking
- test(apparmor): teach Reg stub the all_plugins() contract
- telemetry: emit trace-level input/output on the turn (AGENT) span
- docs(apparmor): de-brittle plugin-count in composer self-filter comment
- fix(telemetry): POST Langfuse spans to the /v1/traces signal path
- telemetry: propagate session.id to child spans for Langfuse best practices
- test: allowlist JAATO_TELEMETRY_BACKEND in session-env audit
- telemetry: pricing-table cost on spans + dedicated Langfuse backend
- telemetry: stamp provider cost on LLM spans + OTLP protocol selection for Langfuse
- fix(session): close the turn lifecycle on solely-%name--help messages
- fix(apparmor): make .jaato/prompts runner-writable so save/deletePrompt work
- test(apparmor): pin that rendered profiles actually COMPILE, not just render
- Revert "Merge pull request #547 from Jaato-framework-and-examples/claude/deleteprompt-apparmor-delete-grant"
- fix(plugins): repoint environment/calculator off the bare jaato facade import
- fix(prompt_library): grant AppArmor delete on writable prompt/skill tiers
- fix(introspection): guardrail against fabricated tool ids leaking to users
- fix(prompt_library): document the placeholder grammar at both authoring surfaces
- feat(session): surface abnormal finish reasons to clients
- docs(doubleword): correct the catalog auto-detect claim (verified live)
- Add Doubleword provider plugin and service_tier knob
- feat(instructions): granular suppress_base_instructions (disk/constants/security)
- fix(context): return 0 (honest unknown), not hardcoded 1M, when provider unmaterialized
- core: read conversation history from the runner (fix empty transcript on cold WS reattach)
- inline profiles: honor the spec's own name (stop dropping it for "<inline>")
- session restore: re-apply the profile's suppress_base_instructions
- test: update session serializer version assertion 2.6 -> 2.7
- session restore: reconstruct inline-profile sessions from a persisted spec
- session_manager: resume WS workspace-pinless sessions via the session-workspace index
- tool_id_map: scrub markdown-escaped tool ids (t\_xxxxxxxx)
- prose_tools: drop the example tool id from the injected preamble
- chrome_ai: add reuse_page to anchor onto an existing tab
- chrome_ai: warm the on-device model at connect() to absorb cold-start
- Add direct-provider smoke for the prose_tool_calls quirk
- Add prose_tool_calls quirk: prose-emulated tool calling for tool-less models
- Add chrome_ai model provider: Chrome built-in AI (Gemini Nano) via CDP
- refactor(facade): ship the `jaato` convenience facade in jaato-sdk (sdk-only client) (#527)
- feat(providers): OVHcloud AI Endpoints model provider plugin (#526)
- feat(sdk): public open_event_stream() — synchronous-subscribe event iterator (#524)
- fix(wake): release wake bindings + index entry on session DELETE (orphan fix) (#523)
- feat(scaffold): `explain events` / `explain event <NAME>` — the event protocol (#522)
- fix(wake): headless client-tool dispatch — whitelist sync + drive-after-wiring (#521)
- feat(server): durable deferred-turn wake (Option 2 — cold-revive-and-act) (#520)
- feat(server): surface daemon wake endpoint on bind_wake (production routing) (#519)
- feat(server): mode-B wake verify shim — daemon-tier HTTP ingress (PR 2b) (#518)
- feat(server): wake binding registry + bind_wake/unbind_wake (PR 2a, mode-B foundation) (#517)
- feat(server): session.wake — client-agnostic daemon wake primitive (PR 1 core) (#516)
- fix(security): validate session_id to close path-traversal / profile-injection (#502)
- fix(permission): trusted bridge suppresses the prompt, not the hard deny-layers (#501)
- feat(mcp): scrub declared secrets from MCP server subprocess env (#10, MCP half) (#500)
- style(webhook): restore CRLF line endings on 3 test files (#499)
- fix(webhook): fail-closed auth — unsigned routes refused unless explicitly opted in (#498)
- fix(web_fetch): code-gate insecure/no_proxy behind operator opt-in (was prose-only) (#497)
- fix(permission): whitelist glob can't auto-allow unauthorized shell operators (#496)
- security: untrusted-content trust boundary for web_fetch/web_search/MCP (#495)
- docs(env): document env vars via # env: comments (#494)
- ops: env-var discoverability — live overrides at startup/--status + explain-env descriptions (#493)
- Security hardening + per-session egress confinement (proxy + cgroup-nft) (#492)
- fix(cascade): dedup post-bootstrap events for an owner==observer (single IPC connection) (#491)
- fix(tool-results): keep result STRUCTURED; move model-facing steering to ToolResult.model_suffix (#490)
- fix(host-tools): decode client-tool results to native dicts (flat), symmetric with in-process tools (#489)
- fix(permission): exempt framework-reserved tools (incl. signal_completion) from the default evaluator — corrects #487 (#488)
- fix(permission): framework core tools are exempt from a catch-all "default" evaluator (#487)
- fix(secret-uri): fail loud on the single-colon `pass:` typo (was leaking as a bearer token) (#486)
- fix(providers): surface the profile api_key knob in APIKeyNotFoundError checked-locations (#485)
- fix(providers): verify_auth reads the `config` param, not self._config (in-process crash) (#484)
- fix(scaffold): library exception states the fact, not a caller-convention hint (#483)
- fix(plugins): concise WARNING for missing-dependency plugin skip during discovery (#482)
- chore(release): bump jaato-server 0.6.194 → 0.6.195 (scaffold extension seam) (#481)
- feat(scaffold): verb-extension point for external (premium) verbs (#480)
- fix(tools): pip shim + venv-bin exec grant so bare `pip`/`!pip` works confined (supersedes #478 ensurepip) (#479)
- fix(tools): materialize pip in workspace_venv so bare `pip`/`!pip` targets the tool-venv (#478)
- feat(notebook): IPython-style per-line !shell escapes (make the tool's own advice work) (#477)
- feat(permission): give evaluator scripts the session's prior-decision journal (EvalContext.execution_log) (#476)
- feat(scaffold): surface + validate non-provider plugin config knobs (permission.evaluators, cli.workspace_venv, …) (#475)
- fix(tools): scope the workspace_venv runner-import bridge to jaato srcs (no base-venv over-share) (#474)
- fix(tools): confined pip for workspace_venv — plugin-scoped distro reads + cli foreground venv activation (#473)
- fix(tools): bridge runner imports into workspace_venv so the notebook kernel can import shared.* (#472)
- feat(tools): workspace_venv knob on cli/interactive_shell/notebook for dynamic tool deps (#471)
- chore(deps): declare wcwidth as a core dependency (#470)
- fix(daemon): orphan-revive recipe loss — persist+restore sandbox_mode (apparmor) AND agent_name (persona/vision) (#469)
- feat(memory): allowed_scopes write-side gate (deployment scope policy) (#468)
- feat(scaffold): reproducible provenance line + `new --transport in_process` (#464)
- feat(scaffold): --ca for --transport ws — scoped wss:// CA (completes #462 alignment) (#463)
- feat(scaffold): support --transport ws --recoverable -> WSRecoveryClient (#461)
- feat(facade): expose recovery as a facade mode — session(mode=…, recovery=True) (#460)
- fix(introspection): keep discovery tools when real tools exist, drop only for empty wire (ex08 lead hang) (#458)
- fix(introspection): gate discovery GUIDANCE with the tools (ex08 0-tool subagent loop) (#457)
- fix(in-process): completion-nudge gate keys on terminal injects, not is_running (ex08 #5C premature-completion) (#456)
- fix(in-process): drive lead completion nudge + emit SESSION_TERMINATED (ex08 gap #5C/#5D) (#455)
- feat(in-process): auto-continue the lead when a subagent injects (ex08 gap #5B) (#454)
- fix(in-process): bridge subagent events to the facade loop (set subagent ui_hooks) (#453)
- fix(subagent): UnboundLocalError in spawn_subagent (conditional get_workspace_root import) (#452)
- fix(in-process): populate session-context workspace_root/config_root for spawn (#451)
- fix(in-process): parse plugin-entry modifiers ((preload)/tool-scopes) like the daemon (#450)
- feat(in-process): forward client_tools (host tools) through the facade (#449)
- fix(session): gate plugin instructions by plugins, not the dead tools alias (+ in-process None/[] IPC parity) (#448)
- fix(in-process): pin config_root on the embedded runtime (~/.jaato isolation leak) (#447)
- docs+scaffold: multi-transport (in-process / IPC / WebSocket) (#445)
- feat(sdk): WSClient — WebSocket transport for the facade (remote daemon) (#444)
- test(in-process): stream() + multi-turn continuity (PR4) (#443)
- feat(in-process): plugin parity — init full runner-tier ONCE at connect (#442)
- fix(daemon): agent without --profile no longer goes bare (persona dropped) (#441)
- feat(in-process): thread suppress_base_instructions (the base-composition knob) (#440)
- feat(in-process): agent-persona resolution (ex03) + lift resolve_agent to shared (#439)
- feat(in-process): AGENT_COMPLETED emission — completion payload reaches the facade (ex04) (#438)
- feat(in-process): profile resolution + system_instructions/completion schema (PR3) (#437)
- fix(in-process): pass the loaded permission plugin so the session gates (ex07) (#436)
- feat(in-process): plugin-loading + permission-channel wiring (InProcessClient) (#435)
- feat(in-process): InProcessChannel permission bridge (PR2 mechanism) (#433)
- fix(in-process): env_file is a both-modes kwarg, not IPC-only (#431)
- feat(in-process): transport-agnostic jaato.session(mode=...) entry (#430)
- feat(in-process): minimal real ex01 path — cred resolve + verify_auth + configure_tools (PR1.5) (#429)
- feat(in-process): InProcessClient adapter — facade tracer-bullet (PR1) (#428)
- feat(config): public resolve_secret_uri entry point (#427)
- feat(mcp): model-callable mcp_reload tool, gated on .mcp.json existing
- fix(provider): fail loud on an unresolved secret-URI api_key (cascade-of-bugs sibling)
- fix(bus): hoist typed signal_completion payload onto the bus event (cascade handoff)
- fix(runner): drain a USER send that races the turn wind-down (multi-turn deadlock)
- fix(clarification): runner→daemon relay so runner-tier sessions can deliver clarifications
- docs(continuity): memory enrichment is curated-only → curator is REQUIRED
- fix(scaffold): send-and-wait client templates no longer hang on a plain turn
- feat(scaffold): validate tags each finding with its source tier (workspace vs user)
- fix(scaffold): validate — model_tiers satisfies the model requirement (no false missing_model)
- feat(daemon): SessionManager.resume_session — public same-id reload + presentation restore (reliability T2)
- feat(daemon): daemon-wide reactor EventBus — per-session buses sink into one bus reactors subscribe to
- feat(daemon): SessionManager.get_persisted_history — read a persisted session's history without loading it
- fix(bundle_common): discover_bundles DEBUG-skips an EACCES-denied tier root (confined user tier)
- feat(daemon): SessionManager.send_message_to_session — drive a turn on a loaded session (same id)
- feat(scaffold): validate prefetch directives — the validate counterpart to explain prefetch
- docs(scaffold): add `explain prefetch` — surface the prefetch-script capability
- fix(re-attach): gate session_get_tool_schemas RPC off-loop (re-entrancy regression)
- fix(re-attach): daemon walk ALWAYS excludes runner-tier + off-loop runner-ready re-emit
- fix(lifecycle): prepare_completion accepts dot-notation into free-shape objects + minProperties floor
- fix(re-attach): tool-id emit skips runner-tier plugins on the loop (re-attach stall)
- fix(prompt_library): mtime-gate _discover_prompts (re-attach loop-stall root cause)
- diag(runner): + daemon-side [RPC_DIAG] _in_flight SET + read_loop RESPONSE (id/in_flight_had/client) to pin the reused-transport reply-match miss
- diag(runner): [RPC_DIAG] trace serve-recv / worker ENTER+EXIT to localize the re-attach register stall (THROWAWAY diag branch, not for merge)
- docs(scaffold): document profile inheritance semantics in `explain profile`
- fix(providers): thread api_params sampling knobs in google_genai/antigravity/github_models/ollama (audit follow-up)
- fix(vllm): thread api_params sampling knobs (temperature/top_p/seed/…) into the request
- fix(runner): gate mid-session client-tool push + send on bootstrap-complete, not rpc-handle-live
- feat(events): bridge gate.released onto the reactor event bus
- fix(restore): resolve config_root on disk-restore so a config_root=None session can't hang the runner
- feat(scaffold): explain paths — the daemon-global vs per-session isolation model
- feat(session): SessionManager.set_session_state_for_session — cross-session state write
- feat(permission): reliability T3 foundation — approved-overrides-escalated
- feat(permission): reliability T1 — deny escalated tools on headless clients
- fix(core): skip conversation replay on attach for chat-type clients
- fix(session): thread attaching client_id into restore-spawn so re-attach re-spawns the runner (#370 follow-up)
- fix(session): close the attach-vs-unload race — the real (a) for the re-attach bug
- fix(core): await runner readiness on send instead of derefing None _runner_rpc (attach race)
- feat(permission): reliability Phase-2 interactive escalation gate (public read-hook)
- fix(scaffold,vllm): stop two validator false positives (api_key credential knob + vllm api_params layer)
- fix(file_edit): _ensure_gitignore must not fight a deliberate .gitignore setup
- fix(provider): scrub tool-hash-ids out of user-facing model narration
- fix(notebook): make kernel preexec_fn fork-safe (hoist ctypes/CDLL out of the fork window)
- fix(notebook): actually use the subprocess kernel (cutover was bypassed) + propagate ContextVar to streaming thread
- fix(notebook): kernel chdir to SESSION workspace via ContextVar; broadcast workspace to all plugins
- feat(notebook): subprocess kernel — PR 3 (lifecycle + cutover to default)
- feat(notebook): subprocess kernel — PR 2 (cross-process tools bridge + permission)
- feat(notebook): subprocess kernel backend — PR 1 (kernel + transport + cwd=workspace)
- fix(client-tools): client/host tools default to 'core' (eager), honor discoverability
- feat(client-tools): mid-session host-tool registration — glue schema to live runner
- fix(model-tiers): cross-provider tier provider got no plugin_configs (no api_key)
- fix(profiles): _merge_profiles dropped model_tiers (inherits/set tiers lost)
- feat(scaffold): explain `tiers` topic + model_tiers vision example (V2 tooling)
- test(model-tiers): seed _provider_cache/_active_provider_name in the __new__ helper
- feat(model-tiers): V2 cross-provider tiers — swap providers on tier switch
- feat(multimodal): ferry user-message attachments to the runner-tier model
- fix(client-tools): call daemon_plugin_execute with keyword args (execution)
- feat(client-tools): IPC transport support + SDK register_client_tools + host-tools scaffold
- fix(client-tools): seed client_tool_schemas before the runner spawn (#349 race)
- feat(client-tools): inject client-provided tools into the runner-tier model
- feat(tooling): runtime-entity debugging — explain runtime + doctor --session
- fix(runner): seed workspace ContextVar + env so path plugins resolve the session
- feat(scaffold): surface the recoverable client (IPCRecoveryClient)
- feat(session): gate introspection on the presence of something to discover
- feat(scaffold): surface discovery-gated (deferred-unless-preloaded) tools
- feat(tooling): WebSocket awareness in doctor, scaffold, and the client skill
- fix(plugins): memory/references/subagent must not self-disable under confinement
- fix(tests): _verify_connectivity stubs must accept the probe_url arg
- refactor(providers): migrate vllm onto OpenAICompatLocalHostProvider (PR7, final)
- refactor(providers): migrate zhipuai_openai onto OpenAICompatProvider (PR6)
- refactor(providers): migrate lmstudio onto OpenAICompatLocalHostProvider (PR5)
- refactor(providers): migrate triton onto OpenAICompatLocalHostProvider (PR4)
- refactor(providers): OpenAICompatLocalHostProvider base + migrate tensorrt_llm (PR3)
- feat(scaffold): explain surfaces config + profile descriptions (self-contained)
- refactor(providers): migrate nebius onto OpenAICompatProvider + lift api_params (PR2)
- refactor(providers): add OpenAICompatProvider base + migrate nim to it (PR1b)
- refactor(providers): relocate shared OpenAI-compat converters + _lazy to _openai_compat
- test(providers): guard that no unhashed tool name reaches the LLM + Anthropic tool_choice shape
- fix(providers): map name-bearing tool_choice through name_to_id (wire id)
- fix(server): --stop/--status find client-autostarted daemons via the socket
- feat(nebius): cached_tokens measurement + extra_body passthrough (vLLM caching)
- fix(server): raw docstring for check_pipe_exists (silence \p invalid-escape warning)
- feat(sdk): doctor daemon-env report drives off the introspected read-set
- feat(sdk): explain provider resolution order + credential-chain contract
- feat(sdk): client doctor + jaato-scaffold tool + provider knob/quirk contract
- feat(providers): PDF input for Anthropic + Google (fast-follows on the contract rails)
- feat(providers): PDF input support (producer + pdf_input capability + OpenRouter marshalling)
- fix(providers): close remaining capability gaps (google tool-result vision, ollama/zhipuai modality)
- fix(providers): Phase 3 — close high-severity capability gaps (NIM-fleet vision, claude_cli honesty)
- feat(providers): model-provider capability contract + CI conformance guard
- fix(multimodal): make the agentic tool-result image path work for OpenAI-compat
- fix(openrouter): marshal user-message image parts in the wire converter
- fix(providers): marshal image parts in the OpenAI-compat converter
- feat(reliability): compute is_error_result on tool.call_completed
- feat(echo): add deterministic creds-free echo model provider
- fix(ephemeral): terminate single-shot ephemeral on turn.completed
- fix(ephemeral): set config_root on scratch/inline spawn so core plugins expose
- fix(ephemeral): decouple inline display-name from agent resolution + provision scratch workspace
- fix(websocket): drop shadowing local import os in _apparmor_session_hook
- feat(subagent): bridge remote-spawn runner->daemon (restore server= under seat-flip)
- fix(telemetry): implement reset_for_next_session + guard the protocol class
- fix: stamp daemon session_id per-session so memory reads it, not shared registry
- fix(plugins): resolve session per-execution in telepathy/memory (no self leak)
- test(env-audit): sync ALLOWLIST — drop 22 migrated entries, add 4 daemon-tier
- test(session-state): expect serializer schema version 2.4
- test(runtime-limits): add required plugins key + opt-in gate cgroup e2e
- test(signal-completion): seed _accumulated_payload + _provider on stubs
- test(deferred-instructions): set _tool_scopes on the __new__-built session
- test(budget): set _tier_config on the __new__-built session stub
- test(visibility-filter): add _apply_tool_scopes to session stub
- test(server-version): pass now-required client_type to IPC client ctors
- test(dynamic-instructions): drop tests for the removed render_completion_artifacts API
- test(enrichment): add reset_for_next_session to stale protocol fixtures
- fix(telepathy): implement ToolPlugin protocol methods so the plugin loads
- fix(apparmor): grant for the loaded runner-tier plugin set, not profile.plugins
- spike: ephemeral remote-spawn via create_headless_session (§7c repair)
- fix(nebius): forward api_params (tool_choice/temperature/...) to chat.completions
- fix(nim): verify_auth must honor the profile-supplied api_key
- fix(nebius): verify_auth must honor the profile-supplied api_key
- feat(providers): Nebius Token Factory provider (serverless, catalog bootstrap)
- feat: config-time vision-tier validation (multimodal PR 4)
- feat: vision tier + content-boundary gate (multimodal PR 3)
- feat(providers): honest vision capability for anthropic/google/antigravity (multimodal PR 2)
- feat(providers): input-modality capability primitive (multimodal PR 1)
- refactor(events): single error-termination chokepoint — structural AgentErrorEvent-before-reason=error invariant
- feat(events): SlotSettledEvent.terminal_reason — fixes slot.settled-vs-recovery double-advance
- refactor(providers): standardize zhipuai context-window resolution (8/8)
- refactor(providers): standardize claude_cli context-window resolution
- refactor(providers): standardize github_models context-window resolution
- refactor(providers): standardize antigravity context-window resolution
- refactor(providers): standardize anthropic + google_genai context-window resolution
- refactor(providers): standardize nim + tensorrt_llm context-window resolution
- feat(events): AgentErrorEvent + on_agent_error recovery contract
- feat(file_edit): correct updateFile anchoring model in the tool contract
- feat(file_edit): allow_full_replace gate + conditional cap-rejection wording
- feat(file_edit): per-profile max_edit_span_chars targeted-edit span cap
- docs: fix three stale framework docstrings (#294/#295/#296)
- refactor(api): rename create_session/configure tools= param to plugins= (deprecated tools= alias)
- fix(result_grep): always emit valid JSON envelope so the full-dict path can't discard filtering
- feat(result_grep): model-directed tool-result grep filtering + greppable_content trait
- fix(providers): emit ALL parallel tool results on the OpenAI-compat wire
- fix(session): gate force_tool_choice stamp on provider honoring the quirk
- fix(cascade): γ'-guard gap pinned discovery slot for minutes (one-slot reuse)
- feat(events): SlotSettledEvent — universal per-cascade-stage handoff signal (replaces SlotReusableEvent)
- feat(events): add agent_id (stage name) to SlotReusableEvent payload
- feat(events): SlotReusableEvent — emit when a pool slot is reusable (cascade warm-reuse)
- fix(lsp): never host a language server in the daemon process (#284 OOM)
- fix(lsp): suppress LSP lifecycle on daemon-side forwarding stub (#284 OOM root cause)
- fix(lsp): kill slot's process-group subtree on teardown (#284 OOM)
- fix(lsp): reap jdtls on slot teardown (atexit + shutdown sentinel)
- fix(lsp): reap orphaned jdtls on connect timeout + raise timeout to 180s
- fix(notebook): strip NUL in apparmor profile parse; clarify gate scope
- security(notebook): fail closed on in-process cell execution
- revert: TEMP instrumentation quadruple (PR-218 / PR-219 / PR-220 / PR-221)
- refactor(session): extract pure tool-result building helpers
- refactor(session): extract tool-result truncation/capping transforms
- refactor(session): extract GC support helpers (span attrs + budget sync)
- refactor(session): extract instruction-budget builder helpers
- fix(gc): also run dedup Phase-0 in the before-send GC path
- refactor(session): extract SessionPersistence collaborator
- feat(gc): wire identical tool-result dedup as session-level GC Phase 0
- refactor(session): extract pure telemetry helpers; drop dead code
- feat(gc): identical tool-result dedup helper (core, tested)
- security(apparmor): loud structured warning + require-confinement gate
- security(cli): fail closed when shlex can't parse a command for sandbox
- security(ipc): default IPC socket mode to 0o660 (owner+group)
- feat(openrouter): flip context-window resolution to auto-detect PRIMARY
- feat(lmstudio): flip context-window resolution to auto-detect PRIMARY
- feat(ollama): tier-1 context-window auto-detect via /api/show
- feat(provider): tier-1 context-window auto-detect from /v1/models (vLLM)
- fix(gc): resolve budget context_limit when lazy provider materializes (#278)
- fix(lsp): spawn language servers with PR_SET_PDEATHSIG=SIGKILL (#280)
- fix(anthropic): accept-and-ignore tool_choice kwarg (provider contract parity)
- feat(gc): GC_DENOM diagnostic — make the budget-GC denominator inspectable
- fix(budget): count the initial wire tool-schema array in the GC denominator
- feat(lifecycle): processor-gated is_complete + server-side auto-finalize
- feat(profile): per-plugin tool allow-list via plugins(...) modifier
- feat(lifecycle): enriched pending-field descriptors for B1 viability
- fix(lifecycle): resolve $ref in prepare_completion validator + pending walker
- fix(lifecycle): adopt Daniel's path-syntax examples in field_path description
- feat(lifecycle): iterate prepare_completion to A2 shape (field_path, value)
- feat(vllm): VLLM_TOOLS_WIRE_DUMP probe — per-tool wire byte sizes
- feat(lifecycle): prepare/query_completion + arg-less signal_completion synthesis
- feat(session): GC_NO_ITEMS_COLLECTED diagnostic with locked-vs-eligible breakdown
- fix(vllm): add force_narration_between_tools to _KNOWN_QUIRKS allow-list
- fix(session): reshape force_narration_between_tools from env var to profile.quirks
- feat(session): JAATO_FORCE_NARRATION_BETWEEN_TOOLS env var + synthetic prompt injection (Probe B)
- feat(providers): parallel_tool_calls profile knob (vllm flat, openrouter api_params)
- feat(gc_budget): preserve narration on orphan-pair removal (Shape D)
- fix(providers): close openai client httpx pool on cancel (Shape B)
- probe(vllm+session): bump cancel-leak traces from self._trace to logger.info
- probe(vllm+session): cancel-leak prod-vs-isolation instrumentation
- feat(providers): explicit response_stream.close() so cancel aborts upstream HTTP
- probe(session+vllm): extend MAYBE_STAMP probe set with consume + complete entry (PR-256)
- probe(session): MAYBE_STAMP_SCAN logger.info at stamp helper entry (PR-255)
- revert: PR-253 post-completion send_message guard (misdiagnosed)
- fix(session): hard-refuse send_message after signal_completion (PR-253)
- fix(stop): reap orphan runners surviving --stop's registry walk
- fix(vllm): hash-translate tool_choice name to match wire tools array
- feat(session+vllm): force_tool_choice_for_lifecycle quirk (Path 1)
- feat(profile+vllm): SubagentProfile.quirks + coerce_typed_tool_args quirk
- feat(smokes): restructure nim/ollama/openrouter/tensorrt_llm to 3-test pattern
- feat(anthropic+github_models+lmstudio/smoke): restructure to 3-test pattern (chat / signal_completion / tools)
- fix(runner): fire post-turn AgentUIHooks for root IPC sessions (Path G)
- feat(vllm/smoke): restructure to 3-test pattern (chat / signal_completion / tools)
- fix(lifecycle): gate signal_completion on completion_payload_schema
- fix(session): terminate turn loop on successful signal_completion
- refactor(plugins): extract share_context to non-core telepathy plugin
- fix(runner): drop falsy ``or None`` coercion on tools list at bootstrap
- feat(profile): require explicit plugins: key + fix tools=None expansion bug
- feat(session+todo): gate plan-required todo tools by visibility filter
- refactor(provider): drop hardcoded env defaults across vllm/trtllm/triton
- refactor(provider): generic mid-stream error messages across vllm/trtllm/triton
- feat(provider): add vLLM provider plugin (mirror of tensorrt_llm)
- fix(server): _resolve_profile honors qualified set/name paths
- feat(provider): surface trtllm/triton mid-stream connection drops with engine-config diagnostic
- refactor(provider): github_models smoke — YAML profiles + signal_completion persona + suppress_base
- refactor(provider): ollama smoke — YAML profiles + signal_completion persona + suppress_base
- refactor(provider): anthropic smoke — YAML profiles + signal_completion persona + suppress_base
- refactor(provider): nim smoke — YAML profiles + signal_completion persona + suppress_base
- refactor(provider): lmstudio smoke — YAML profiles + signal_completion persona + suppress_base
- fix(provider): wire max_tokens knob in tensorrt_llm
- refactor(provider): canonical tensorrt_llm smoke — YAML profiles + signal_completion persona + suppress_base
- docs(openrouter): fix stale .json references in README — tree diagram + manual path
- fix(provider): openrouter smoke — YAML profiles, signal_completion persona, max_tokens cap, suppress_base
- fix(runner): propagate suppress_base_instructions + system_instruction_override over the wire
- fix(provider): wire api_params.max_tokens in openrouter
- feat(provider): github_models smoke harness mirroring tensorrt_llm pattern
- feat(provider): anthropic — smoke harness mirroring tensorrt_llm pattern
- feat(provider): nim smoke harness (mirrors tensorrt_llm pattern)
- feat(provider): lmstudio smoke harness (mirrors tensorrt_llm pattern)
- feat(provider): smoke harness for openrouter (mirror of tensorrt_llm)
- feat(provider): ollama smoke harness (mirrors tensorrt_llm pattern)
- refactor(provider): smoke — model in profile, host via workspace .env
- feat(provider): bootstrap.sh — optional --run chat|tools
- refactor(provider): bootstrap.sh — bootstrap-only, no run step
- feat(provider): run_smoke.sh — one-shot bootstrap + run for smoke harness
- fix(provider): smoke harness — ErrorEvent.error + optional --workspace
- fix(provider): drop redundant "permission" entry from tools-smoke profile
- feat(provider): tensorrt_llm tools smoke alongside chat smoke
- feat(provider): tensorrt_llm smoke harness + workspace templates
- feat(lsp): bounded-poll convergence wait for jdtls multi-stage publishDiagnostics
- feat(sdk+core): expose ToolResult.enrichment_metadata on the tool-call ledger
- probe(lsp): TEMP — narrow get_diagnostics await + publishDiagnostics path
- probe(lsp): TEMP instrumentation inside LSPToolPlugin.enrich_tool_result
- probe(core): TEMP instrumentation — narrow enrich subscriber dispatch (B-i/ii/iii/iv)
- probe(core): TEMP instrumentation — narrow enrich_tool_result dispatch gap
- feat(core): Family IV — jdtls state sibling-of-workspace + ${jdtlsStateRoot} template var
- fix(core): replay_messages must call _ensure_provider (lazy-INIT refactor missed)
- cleanup(core): remove SessionManager.ensure_session_loaded — wrong abstraction
- fix(core): SessionState.config_root + RuntimeSessionInfo listing reference
- feat(core): SessionState.profile_name; retire Google-coupled project/location/model
- feat(core): SessionManager.ensure_session_loaded — programmatic rehydration without attach
- feat(core): cascade.cancel(cid) IPC verb + reactor-suppression predicate
- fix(core): promote entry-point Protocol-check trace to WARNING with named missing methods
- feat(core): DaemonForwardingMixin + PLUGIN_TIER="daemon_callable" cross-tier pattern
- fix(core): dedup compares delivery_target_id (raw connection id), not namespaced registration id (#208)
- fix(core): dedup bootstrap-time event delivery when client is both direct-attached and cascade observer (#207)
- fix(core): dedup AgentCreatedEvent on main-agent bootstrap (#206)
- feat(sdk): add session_id field to AgentCreatedEvent (#205)
- feat(template): reject None-valued kind=scalar (close third empty-equivalent state) (#204)
- feat(template): dual-engine (Mustache + Jinja2) required-scalar enforcement at renderTemplateToFile boundary (#203)
- Revert "feat(template): top-level required-scalar enforcement + Spring sentinel parser-protection (#202)"
- feat(template): top-level required-scalar enforcement + Spring sentinel parser-protection (#202)
- feat(render-context): expose session_id with parent-walk resolution (#201)
- feat(template): recursive item_keys traversal at renderTemplateToFile boundary (#200)
- feat(template): helper-exclusivity validation at renderTemplateToFile boundary (A2) (#199)
- fix(bootstrap): emit SessionTerminatedEvent on bootstrap failure (visibility-gap close) (#198)
- fix(memory): source_session wired via config + live registry (PR-196 follow-up) (#197)
- fix(memory): wire set_session(session) so source_session is populated (#196)
- feat(provider): TensorRT-LLM via trtllm-serve (OpenAI-compatible) (#195)
- fix(cascade): bootstrap-time events route to cascade observers (centralized helper) (#194)
- fix(cascade): auto-detach IPC clients from cascade-stamped sessions on terminal events (γ') (#193)
- fix(cascade): stamp cascade_driver_id on Session dataclass (Bug B real root cause) (#192)
- chore(script_loader): probe-symbol-missing → DEBUG, not WARNING (#190)
- fix(bus): bridge SessionTerminatedEvent to EventBus (Bug C) (#189)
- fix(cascade): GC sweep mid-cascade reap (Bug B) (#188)
- feat(processor): ProcessorResult TypedDict + jaato_sdk.cascade_authoring umbrella (#187)
- feat(events): carry error context onto SessionTerminatedEvent (Q2) (#186)
- fix(cascade): default policy unloads on all terminal reasons, not just error (#183)
- hotfix(cascade-as-client): Phase 1.1 — register_in_process_client idempotent on duplicate client_id (#182)
- feat(cascade-as-client): Phase 2 — SDK IPC RPC verbs + disconnect cleanup (#180)
- hotfix(core): emit terminal events on completion-nudge exhaustion (Finding D) (#179)
- feat(cascade-as-client): Phase 1 — daemon-side registry + dispatch + default lifecycle policy (#178)
- hotfix(anthropic): re-raise SDK network-layer exceptions instead of swallowing into TurnResult (#177)
- hotfix(retry): classify anthropic SDK APIConnectionError + APITimeoutError as transient (#175)
- hotfix(runner): session.end clears _session_host + fires close_session hook (#174)
- hotfix(rpc): RunnerRPCClient lives on PoolSlot, reused across cascade sessions (#173)
- hotfix(session_manager): add cascade_driver_id kwarg to create_headless_session (#172)
- hotfix(plugins): inject NO-OP reset_for_next_session into 39 plugins (P0 cascade-sharing regression) (#171)
- feat(cascade-sharing): Phase 4 — LSP plugin lifecycle pin tests (#169)
- feat(cascade-sharing): Phase 3 — per-session apparmor with cross-session transitions (#168)
- feat(cascade-sharing): Phase 2 PR-B — end-to-end IPC + teardown wiring (#167)
- feat(cascade-sharing): Phase 2 PR-A — pool-side slot reuse + session.end RPC (#163)
- feat(cascade-sharing): Phase 1b — reset_for_next_session for 5 review-required plugins (#161)
- feat(cascade-sharing): Phase 1a — reset_for_next_session protocol + 8-plugin audit (#160)
- fix(lsp): add plugin_configs.lsp.apparmor_extra_rules operator knob (profile YAML) (#158)
- fix(lsp): symmetric workspace_path resolution at connect_server (PR-156 follow-up) (#157)
- fix(lsp): auto-inject TMPDIR from -data path to sidestep jdtls eager-tempdir bug (#156)
- fix(lsp): auto-emit apparmor grants for -data / --data-dir paths in .lsp.json args (#155)
- fix(lsp): get_apparmor_rules emits ix grants for configured LSP server binaries (#154)
- fix(lsp): debug_log_path knob + apparmor fragment closes silent-config-cache-reset (#153)
- fix(lsp): port validate_snippet to await_diagnostics (PR-3 follow-up) (#152)
- fix(lsp): bounded-poll for publishDiagnostics via asyncio.Event (#151)
- fix(lsp): expose plugin_configs.lsp.connect_timeout_seconds for heavy-init servers (#150)
- fix(runtime): promote plugin_configs.<provider>.api_key to ProviderConfig.api_key (#149)
- fix(apparmor): split registry creation so composer can query plugins (#148)
- fix(file_edit): complete apparmor fragment + drop workspace fallback (#147)
- refactor(registry): pre-init framework-key injection layer fix (#146)
- fix(file_edit): export get_apparmor_rules + thread workspace/config_root through plugin_configs (#145)
- fix(file_edit): anchor backups on config_root (corrects PR-143 misdirection) (#144)
- fix(file_edit): anchor backup path on workspace_root, not daemon CWD (#143)
- refactor(completion): unify completion_artifacts + completion_validators into completion_processors (#142)
- fix(profile): env_file overlay in _resolve_profile so JAATO_PROFILE_SET reads (#141)
- fix(provider): expand plugin_configs daemon-side + JAATO_ZHIPUAI_API_KEY env var (#140)
- fix(completion): wire completion_validators (+ artifacts) through runner envelope (#139)
- feat(completion): kb-authored semantic validators for signal_completion (#138)
- feat(tui): render human template names in tool tree (post-#136 follow-up) (#137)
- feat(template): hash template identifiers at LLM boundary (mirror of tool-name hashing)
- feat(openrouter): expose strict_tools profile knob (Approach A)
- docs(signal_completion): correct strict-mode claim + warn about model support
- feat(apparmor): plugin-contribution refactor Phase 5 (helper + contract test)
- feat(apparmor): plugin-contribution refactor Phase 4 (agents + profiles + isolated-subprofile gap)
- feat(signal_completion): expose completion_payload_schema as flat tool args (Option G)
- feat(apparmor): plugin-contribution refactor Phase 3b (gc.json)
- feat(apparmor): plugin-contribution refactor Phase 3 (service_connector + references catalog)
- feat(apparmor): plugin-contribution refactor Phase 2 (memory + prompt_library)
- perf(references): skip embedding provider load when no bundles (Fix A)
- fix(cli): bind module-level logger (PR #124 regression)
- fix(apparmor): propagate JAATO_APPARMOR_COMPLAIN to tool_hat + //child sub-profiles (template v22)
- diag(cli): CLI_SUBPROCESS_ENV log line at Popen call sites
- feat(apparmor): references plugin migration + WS-side wiring (Phase 1, template v21)
- feat(apparmor): plugin-contribution hook (Phase 0, template v20)
- diag(runner_spawn): surface error_type + error on bootstrap-failure WARNING
- diag(apparmor): env-gated complain mode toggle (JAATO_APPARMOR_COMPLAIN)
- diag(model_thread): MODEL_THREAD_TERMINAL_ERROR INFO log at ErrorEvent emit
- fix(provider+model_thread): vendor-correct error text + session-terminal on provider errors
- diag(anthropic-provider): emit PROVIDER_RESPONSE_DUMP on the exception path too
- diag(anthropic-provider): fix response dump attribute name
- diag(anthropic-provider): dump request + response when JAATO_DUMP_PROVIDER_REQUEST set
- fix(runner): disable PR-112 plugin-init gate at the call site (#114)
- fix(introspection): reframe explore-tools guidance from "ALWAYS" to "WHEN REQUIRED" (#113)
- perf(registry): gate plugin initialize() on session-requested set (option C) (#112)
- fix(apparmor): //child fragment-only exec — strip broad ix grants (template v18) (#111)
- fix(subagent): _scan_profiles_dir summary log lists per-pass names only (#110)
- fix(apparmor): grant change_profile -> //child in parent body (template v17) (#109)
- feat(perf): instrument runner-side plugin configure with BootstrapTimer (#108)
- feat(apparmor): per-profile fragment scoping (Piece 1 task-64) (#107)
- fix(apparmor): unify config_root/env_file threading via envelope (closes headless cascade crash) (#106)
- feat(apparmor): profile field + caller-kwarg surface (PR-A back-compat) (#105)
- fix(runner): propagate profile.model_tiers via envelope (enter_tier regression) (#104)
- fix(server): defer session unload to background thread (asyncio-deadlock fix) (#103)
- fix(runner): //child install reads envelope.profile_name (closes pool-slot apparmor escape)
- fix(runner): profile-less envelope falls back to session env (no hardcoded anthropic)
- feat(runner): flip JAATO_RUNNER_POOL_ENABLED default to true + docs (pool PR 5e)
- feat(runner): pool telemetry counters via get_telemetry (pool PR 5d)
- feat(runner): template-ready handshake replaces 2s sleep (pool PR 5c)
- feat(runner): subreaper + template watchdog auto-respawn (pool PR 5b)
- fix(runner): dispatch session.bootstrap on main thread (PR 5a fix)
- feat(runner): per-slot AppArmor self-confine via envelope.profile_name (pool PR 5a)
- fix(runner): daemon-resolved session_env via envelope (fixes PR #91 AppArmor regression)
- feat(runner): relocate workspace .env reading to runner-side bootstrap_session (Shape 3 PR 1)
- feat(runner): route session bootstrap through pre-warm pool + replenishment (pool PR 4)
- feat(runner): pool slot manager + fork-slot RPC (pool PR 3)
- feat(runner): pre-warm template subprocess (pool PR 2)
- fix(session): defer provider INIT to first model use (pre-warm pool PR 1)
- fix(runner-rpc): wire remaining 6 runner-side ServerAgentHooks methods
- fix(runner-rpc): wire on_agent_completed + on_session_quiescent across §7c
- fix(runner): thread agent_id from envelope through create_session
- fix(runner_spawn): build_session_envelope agent_id + completion_payload_schema
- fix(apparmor): write-deny <workspace>/.jaato/apparmor-fragments/**
- feat(apparmor): workspace-tier fragment discovery
- fix(apparmor): v16 template grants mmap-exec on venv C-extensions
- feat(apparmor): Phase 5 §5.9 — supervisor-declared sub-profile tightening flags
- feat(openrouter): emit X-OpenRouter-Categories for app rankings
- feat(openrouter): cross-model fallbacks, beta headers, routing docs
- feat(openrouter): align streaming with OpenRouter spec
- fix(file_edit): microsecond-resolution backup timestamps + collision counter
- feat(runner-rpc): Phase 5 §5.8 — profile_payload typed validator
- feat(runner): Phase 5 §5.10e — skip //child install for sub-runners
- feat(interactive_shell): Phase 5 §5.10d — PTY spawn transitions into //child
- server: pre-set TMPDIR=/tmp/jaato-<session> for confined runner subprocess
- server: Phase 5 §X — fix runner self-confine read-rule (template v15)
- server: JAATO_CGROUPS_ROOT env var for non-default cgroup parent
- fix(runner): Phase 5 §5.10c peer-review — audible failure on install gap
- feat(cli): Phase 5 §5.10c — cli plugin transitions subprocesses into //child
- feat(apparmor): Phase 5 §5.10a/b — //child sub-profile + transition callback
- feat(cgroups): Phase 5 §5.3 — orphan sub-cgroup reaper at cascade teardown
- feat(session_manager): Phase 5 §5.2 — nesting-visibility instrumentation
- feat(runner): Phase 5 §5.1b — forward RuntimeLimits app fields to mainline runner
- feat(subagent): Phase 5 §5.1 — apply default RuntimeLimits on isolated spawn
- fix(subagent): Phase 4 §4.3 peer-review — remove silent isolation downgrade + test typo + envelope v2
- test: Phase 4 §4.3.8 — isolated-subagent integration test
- feat(subagent): Phase 4 §4.3.7 — SubagentPlugin opt-in routes to isolated spawn
- feat(forward): Phase 4 §4.3.6d — parent-cascade teardown for isolated subagents
- feat(forward): Phase 4 §4.3.6c — session.bootstrap + first-turn prompt dispatch
- feat(forward): Phase 4 §4.3.6b — cross-runner output forwarding scaffolding
- feat(spawn): Phase 4 §4.3.6a — sub-runner subprocess spawn + handle bookkeeping
- feat(cgroups): Phase 4 §4.3.5 — sub-cgroup provisioning + AppArmor rollback
- feat(apparmor): Phase 4 §4.3.4 — sub-AppArmor profile generation
- feat(spawn): Phase 4 §4.3.3 — SessionManager._spawn_isolated_runner helper + handler bridge
- feat(rpc): Phase 4 §4.3.2 — spawn_isolated_runner RPC primitive (stub)
- feat(subagent): Phase 4 §4.3.1 — isolated-subagent opt-in detection (stub)
- permission+prompt_operator: Phase 4 §4.2 — editable_metadata propagation (J.B closure)
- session+runner+core: Phase 4 §4.4 — description-callback bridge (Finding 2 closure)
- permission+prompt_operator: Phase 4 §4.1 — call_id propagation (J.A closure)
- tests: Phase 4 §D regression pins + bump server to 0.6.75
- server: Phase 4 §D — agent_params propagation to runner via BootstrapEnvelope
- tests: Phase 4 §C regression pins — plugin_configs envelope v2 + permission propagation
- server: Phase 4 §C — profile.plugin_configs propagation to runner (envelope v2)
- openrouter: leverage OpenRouter prompt caching
- server: bump version to 0.6.73 for Phase 4 §B env-propagation fix
- tests: Phase 4 §B regression pins — pre-spawn env resolution contract
- server: Phase 4 §B — resolve workspace .env pre-spawn so runner inherits
- core+runner+session_manager: strip Path G cycle 8-10 probes (post-cycle-13 cleanup)
- prompt_operator: Path J fix — emit PermissionInputModeEvent companion alongside PermissionRequestedEvent
- core: Path I fix — emit AgentCreatedEvent daemon-side at bootstrap
- session_manager: Path H fix — defer incremental save off the _emit_to_session critical path
- core+session_manager: Path G+ probes — diagnosis was wrong, gap is downstream of server.emit
- core+runner: Path G instrumentation — 6 DEBUG probes to localize streaming silent failure
- core+runner: Path F fix — bridge runner→daemon AgentUIHooks gap
- core+runner+serializer: Path E fix — close send_message active-turn chain
- runner: Path D fix — mirror daemon _run_load_plugins runner-side
- shared+runner: Path C fix — runner-side runtime.connect() in bootstrap_session
- session_manager: Path B fix — IPC sessions now dispatch session.bootstrap synchronously
- core: post-Step-7 regression fix — defensive snapshot wrap (Path A)
- core: §7c Step 7.3 — respond_to_permission dual-path routing
- runner: §7c Step 7.2 — wire runner-internal RunnerRPCClient onto registry
- core: §7c Step 7.1 — wire PromptOperatorHandler in set_runner_rpc
- core+runner: §7d — runner-subprocess cgroup attach (peer-review v2 obs #2 realized)
- core: §7c step 6.6.4.5e — atomic _jaato field removal (seat-flip moment)
- core: §7c step 6.6.4.5d — daemon-direct JaatoRuntime construction (Path A transitional)
- runner+core: §7c step 6.6.4.5c.5 — session.get_tool_schemas RPC (Path D finale)
- runner+core+command_router: §7c step 6.6.4.5c.4 — session.get_model_completions RPC (2 callsites, scope expanded)
- runner+core: §7c step 6.6.4.5c.3 — session.execute_user_command RPC (Path A per-type reconstruction)
- runner+core: §7c step 6.6.4.5c.2 — session.get_user_commands RPC (dict-shape wire format)
- runner+core+shared: §7c step 6.6.4.5c.1 — session.get_auth_info RPC + JaatoSession public method
- core+session_manager: §7c step 6.6.4.5b — migrate 15 daemon-side reads to existing runner-RPCs
- session_manager+websocket: §7c step 6.6.4.5a — migrate _jaato.get_runtime() reads to direct _runtime
- core: §7c step 6.6.4.4 — narrow WIRING deletions (3 safe-only sites)
- core+runner: §7c step 6.6.4.3b — atomic seat-flip (send_message → runner-RPC + 9-callback collapse + 7-wiring delete + handler install)
- runner+core+shared: §7c step 6.6.4.3a — session.try_completion_nudge RPC + JaatoSession public method
- runner: §7c step 6.6.4.2 — runner-side session-callback notification-emission machinery
- runner+core: §7c step 6.6.4.1 — notification-frame protocol on session.send_message stream channel
- session_manager+core+websocket: §7c step 6.6.3.6 — migrate 17 external get_session() callers + drop public method
- runner+core: §7c step 6.6.3.5 — session.resolve_fork_point RPC
- runner+core: §7c step 6.6.3.4 — session.replay_messages RPC
- runner+core+shared: §7c step 6.6.3.3 — session.set_parallel_tools_override RPC + JaatoSession public method
- runner+core+shared: §7c step 6.6.3.2 — session.snapshot_conversation_budget RPC + JaatoSession public method
- runner+core+shared: §7c step 6.6.3.1 — session.append_history_message RPC + JaatoSession public method
- runner+core: §7c step 6.6.1.3 — session.restore_conversation_budget RPC handler + wrapper
- runner+core: §7c step 6.6.1.2 — session.restore_turn_accounting RPC handler + wrapper
- runner+core: §7c step 6.6.1.1 — session.set_initial_history RPC handler + wrapper
- shared+server: §7c step 6.6.1.0 — add JaatoSession.restore_turn_accounting + restore_conversation_budget; migrate session_manager
- core: §7c step 6.5 — migrate 4 CLEAN introspection sites to self._runtime
- core: §7c step 6.3 — drop 6 of 7 write-both daemon-side legs (set_reference_authorizer split out)
- core: §7c step 6.2 — migrate 6 straightforward get_session() readers
- runner+core: §7c step 6.1 (3/3) — session.inject_prompt RPC handler + wrapper
- runner+core: §7c step 6.1 (2/3) — session.snapshot_instruction_budget RPC handler + wrapper
- runner+core: §7c step 6.1 (1/3) — session.set_reference_authorizer RPC handler + wrapper
- runner: pre-step-6 toolbar-coherence test + step 5 fold-into-step-6 doc revision
- core: §7c step 4 first pass — daemon-side self._runtime field + 5 get_runtime() migrations
- core: §7c step 3b — public get_tool_schemas accessor replaces private session._tools read
- core: §7c step 3a — public JaatoClient.set_agent_identity replaces private-attr reaches
- core: §7c step 2 — WS-side bootstrap parity; extract shared dispatch_bootstrap_envelope helper
- core: §7c step 1 — IPC always bootstraps runner-side session; remove JAATO_RUNNER_HOSTS_SESSION flag
- runner+runner_rpc_client: session.send_message handler + wrapper (Phase 3 §7b.2 — the big one)
- core: post-init terminal_width sync forwards to runner (Phase 3 §7b.1 lifecycle straggler)
- runner: add session.get_context_limit RPC handler + wrapper (Phase 3 §7b.1 precursor)
- docs+core: §7b.1 audit appendix — per-site bucket classification
- core: JaatoServer.stop forwards cancellation to runner-side session (Phase 3 §7b.1)
- core: JaatoServer.clear_history forwards reset to runner-side session (Phase 3 §7b.1 — first stateless migration)
- websocket: always-spawn runner for WS-provisioned sessions (Phase 3 §7a WS counterpart)
- session_manager+runner_spawn: always-spawn the runner (Phase 3 §7a — first seat-flip-proper commit)
- docs+session_manager: address peer-review C1+C2+M1-M4+Mn1 on §3.3c surface
- runner: add session.get_turn_accounting RPC handler + wrapper (Phase 3 §3.3c precursor)
- runner: add session.reset RPC handler + wrapper (Phase 3 §3.3c precursor)
- runner: end-to-end integration test for the §3.3c dispatch surface lifecycle
- runner + core: session.set_presentation_context handler + JaatoServer migration (Phase 3 §3.3c)
- core: JaatoServer.terminal_width setter forwards to runner-side session (Phase 3 §3.3c migration)
- runner: add session.get_all_session_state bulk-snapshot RPC handler (Phase 3 §3.3c precursor)
- runner: add session.set_terminal_width + session.set_streaming_enabled RPC handlers (Phase 3 §3.3c precursors)
- core: JaatoServer.shutdown calls runner-side session.shutdown before transport close (Phase 3 §3.3c migration)
- runner: add session.shutdown RPC handler + wrapper (Phase 3 §3.3c precursor)
- runner/rpc: serialize real Message dataclasses in session.get_history (Phase 3 §3.3c precursor fix)
- runner_rpc_client: expose session-method named-method wrappers (Phase 3 §3.3c precursors)
- runner: add session.get_history + session.get_context_usage RPC handlers (Phase 3 §3.3c precursors)
- runner: add session-state + lifecycle RPC handler batch (Phase 3 §3.3c precursors)
- runner: add session.health_check RPC handler (Phase 3 §3.3c precursor)
- session_manager: defer-and-flush foundation for disk-restored sessions (Phase 3 §3.12 + peer-review M5/N1)
- session_manager: route ephemeral path through unified bootstrap sub-helper (Phase 3 §3.12 ephemeral)
- session_manager: route _load_session_impl through unified bootstrap sub-helper (Phase 3 §3.12 disk-restore)
- session_manager: relocate IPC apparmor hook inline + remove _planned_sandbox_mode (Phase 3 §3.13)
- websocket: convert apparmor pre-init hook to 4-arg + wire runner spawn (Phase 3 §3.12 WS path)
- session_manager: add BootstrapEnvelope + unified _bootstrap_session helper (Phase 3 §3.12.0)
- subagent: add session-termination hook for plugin state cleanup (Phase 3 §3.11 + peer-review M4)
- shared: add atomic_write helper + migrate framework persistence sites (Phase 3 §3.14)
- runner: lift _telemetry off result dict onto envelope.telemetry (Phase 3 §3.15)
- permission: hold _policy_lock across ASK rule-recheck + channel-wait (Phase 3 §3.7 + peer-review M3)
- permission: wire _get_channel() to select RunnerRPCChannel when runner-side (Phase 3 §3.7 deeper)
- permission: add RunnerRPCChannel ASK relay (Phase 3 §3.7 deeper)
- plugins: migrate stateful plugins (permission, references, memory) to RunnerForwardingMixin (Phase 3 §3.7 §3.8 §3.9)
- cli: collapse Phase 2 _execute_via_runner onto RunnerForwardingMixin
- plugins: migrate wave 2 (4 subprocess-spawning plugins) to RunnerForwardingMixin (Phase 3 task 3.5)
- plugins: migrate wave 1 straggler + waves 3 + 4 (12 plugins) to RunnerForwardingMixin (Phase 3 §3.4 §3.6 §3.10)
- plugins: migrate wave 1 (8 pure-FS plugins) to RunnerForwardingMixin (Phase 3 task 3.4)
- shared: RunnerForwardingMixin for runner-tier plugin stubs (Phase 3 §3.4 prerequisite)
- runner: route tool.execute through session host's executor (Phase 3 task 3.3c part 3a)
- server: build + auto-send session envelope from spawn site (Phase 3 task 3.3c part 2)
- runner: session.bootstrap RPC end-to-end (Phase 3 task 3.3c part 1)
- plugins: PLUGIN_TIER annotation + tier-filtered discovery (Phase 3 task 3.3.5)
- runner: runner-side session host scaffolding (Phase 3 task 3.3b)
- shared: SessionInitEnvelope schema + round-trip tests (Phase 3 task 3.3a)
- runner: apparmor.add_reference_fragment RPC primitive (Phase 3 task 3.2.2)
- runner: client.prompt_operator RPC primitive (Phase 3 task 3.2.1)
- runner: bidirectional RPC — runner-side outgoing + daemon-side incoming dispatch (Phase 3 task 3.2)
- server: rename runner_rpc.py → runner_rpc_client.py (Phase 3 task 3.2 prelude)
- runner: tool-result path-redaction sanitize (Phase 3 task 3.1)
- server 0.6.72: clear os.environ workspace keys in run_in_fresh_session_context
- server: move IPC apparmor hook to pre-init + spawn runner inside _create_session_impl (Phase 2 task 2.3 review fix)
- tests: Phase 2 integration + sister tests (Phase 2 task 2.6)
- cli: route _execute through the runner when one is attached (Phase 2 task 2.5)
- server: wire RunnerSpawner + RunnerRPCClient into IPC sessions (Phase 2 task 2.3)
- server: add server/runner/ package skeleton (Phase 2 task 2.2)
- shared: factor framing into shared/framing.py (Phase 2 task 2.4)
- server: remove daemon-thread per-session AppArmor confinement (Phase 2 task 2.1)
- server 0.6.71: fresh contextvars.Context per session-bootstrap (closes long-lived-daemon ContextVar inheritance leak)
- server 0.6.70: O(1) helper-mtime check via name index (closes cascade dispatch lag)
- server 0.6.69: snapshot sys.modules.values() in _module_with_file
- server 0.6.68 fixup: bundle.py inline-import get_config_root
- server: restore mixed line endings in 0.6.68 migrated files
- server 0.6.68: per-task workspace_root / config_root via ContextVar
- server 0.6.67: .env secret URIs + streaming suffix + catalog gate + headless API default
- server 0.6.63: re-apply signal_completion filter in set_presentation_context
- server 0.6.62: gate completion-nudge + executor on signal_completion exposure
- server 0.6.61: hide signal_completion in interactive root sessions
- docs(script_loader): document lock-scope + partial-import corner case
- server 0.6.60: script_loader sys.modules cache invalidation
- server 0.6.59: artifact_tracker + waypoint consume set_workspace_path
- sdk 0.11.0: relocate classify_template_evaluation_kind to SDK boundary
- server 0.6.58: public classify_template_evaluation_kind helper
- server 0.6.57: secret-URI sane on http/https/${VAR} + call_service endpoint-by-name
- server 0.6.56: TemplateIndexEntry.skip_when_flags — config-flag-driven render skip
- server 0.6.55: profile template v13 — narrow per-subpath denies + tool_hat sub-profile
- server 0.6.54: inotify pressure soft-warn for long-lived daemons
- server 0.6.53: framework-subtree carve-outs in .jaato deny rule
- server 0.6.52: profile template v11 — deny .jaato/** writes from confined sessions
- server 0.6.51: surface DynamicInstructionsError + empty headless session_id at log level
- server 0.6.50: confine prefetch — wrap dynamic-instructions in apparmor_confine
- server 0.6.49: pre-initialize hook API; AppArmor profile loads before configure()
- server 0.6.48: dynamic_instructions abort on prefetch failure + ?-modifier opt-in
- server 0.6.47: SafeThreadPoolExecutor with pre-task hooks closes apparmor stuck-worker EACCES gap
- server 0.6.46: nested-iteration item_keys + inherited_from_outer_scope flag
- server 0.6.45: transport-agnostic client-disconnect helper closes IPC inotify leak
- docs/design: payload-schema-conventions — unify spawn + completion
- server 0.6.44: template_evaluation_kind + helper_siblings on parser surface
- server 0.6.43: per-item item_keys coverage validation + source taxonomy
- server 0.6.42: TemplateIndexEntry carries variant_key + variant axis fields
- server 0.6.41: strip Output-directive line from rendered content (companion to 0.6.35 polyglot)
- server 0.6.40: declarative path-routing rules from .jaato/template_routing.yaml
- server 0.6.39: listTemplateVariables honors index entry's output_path_template (index-authoritative)
- server 0.6.38: Mustache parser recognises Handlebars helpers + filters iteration metadata
- server 0.6.37: empty-segment validation for auto-derived output_path
- server 0.6.36: listTemplateVariables merges body + Output-directive variables
- server 0.6.35: polyglot Output-directive extraction + README documents the convention
- server 0.6.34: renderTemplateToFile auto-derives output_path from template directive
- server 0.6.33: serialise pybars3 calls; thread-local stripped-comment-lines
- server 0.6.32: shape validator allows list-of-scalars when item_keys is empty
- server 0.6.31: renderTemplateToFile shape validation (Mustache-only)
- server 0.6.30: listTemplateVariables strips // host-language comment lines
- server 0.6.29: listTemplateVariables — three parser bugfixes (triple-brace + inverted-branch + nested-section attribution)
- server 0.6.28: listTemplateVariables returns structural info (kind + item_keys)
- docs+lifecycle_tools: completion_payload_schema authoring conventions
- server 0.6.27 + sdk 0.10.0: SessionTerminatedEvent + cancellation-aware end_session
- server 0.6.26: template plugin honors config_root (mirror references plugin)
- server 0.6.25: apparmor_confine — defensive unconfined-reset on entry
- server 0.6.24: anthropic + zhipuai profile config namespacing + sampling params wired
- server 0.6.23: openrouter profile config namespacing (api_params/routing/framework_overrides)
- server 0.6.22: profile-level suppress_base_instructions field
- server 0.6.21: openrouter history shape repair for strict upstreams
- server 0.6.20: openrouter provider — strict-upstream tool-def sanitizer + profile-driven sampling params
- server 0.6.17: profile-set selector + audit guard for session-tied env vars
- server 0.6.16: profile-set overlay nests under profiles/<set>/
- server 0.6.15: preserve preloaded tools through initialize-time core-tool merge
- server 0.6.14: subagent plugin threads completion_payload_schema + completion_artifacts to runtime.create_session
- server 0.6.13: list_tools soft-nudge for preloaded tools
- server 0.6.12: completion_artifacts gain optional output + description
- server 0.6.11: schema-loaders drop auto-prefix — match script_loader convention
- server 0.6.10: extend spawn_payload_schema validation to headless/IPC sessions
- server 0.6.9: typed spawn_subagent — symmetric to typed signal_completion
- server 0.6.8: subagent profile-set overlay via JAATO_PROFILE_SET env var
- apparmor: correct misleading escape-vector comment + denylist /proc/**/attr/**
- server 0.6.7: subagent spawn passes config_root to _resolve_agent
- server 0.6.6: silent skip for sibling-registry modules in directory discovery
- server 0.6.5: register bundle plugin entry-point
- server 0.6.4: completion-artifacts — output-side body-wired rendering (#52)
- server 0.6.3: fix NameError in subagent agent_params threading
- server 0.6.2: dynamic-instructions step 2 — {{!py:script.py}} with full session wiring (#51)
- test: thread config_root through test_connect_creates_runtime_with_provider
- test: untie test_template_version from a hardcoded number
- server 0.6.1: AppArmor dispatch + subagent profile resolution + completion-nudge guard (#49)
- openrouter_auth README: add profile examples for thinking knobs
- openrouter: support enable_thinking / thinking_budget / thinking_level knobs
- openrouter: support provider-routing dict in profile config
- openrouter: add provider + auth plugin
- openrouter: scaffold provider package (env, errors, converters, auth)
- tests: e2e for runtime_limits profile loading → cgroup wiring
- sdks: align bridged payloads + tests with gap 1-5 wire shapes
- release: coordinated bump for gap 1-5 SDK release
- sdks: protocol-version compat (gap 5)
- sdks: subscribe API, profile picker, inline session spec, cost/usage refactor
- fix: propagate --agent <name> to session._agent_id
- gc: resolve gc.json against workspace, add ~/.jaato fallback
- subagent: register ProfilesEntryHandler — second domain validates the architecture
- bundle: document why 'merge' stays references-specific
- bundle: lift create / delete / reconcile to the top-level command
- bundle: lift pack / unpack to the top-level bundle command
- bundle: introduce top-level 'bundle' command for multi-kind ops
- bundle_common: lift pack/unpack into shared module + v2 multi-kind format
- bundle_common: define BundleEntryHandler protocol + registry
- bundle_common: extract domain-agnostic bundle infra into a shared module
- references: nest 'bundle' as a subcommand of references (not a standalone)
- references: split into 'references' (refs) and 'bundle' (bundles) commands
- references: pack / unpack subcommands for bundle distribution
- references: scope:name bundle ref syntax + cross-tier merge / reconcile
- references: two-tier bundle discovery (workspace + user) with shadow precedence
- Fix AgentCompletedEvent.token_usage shape regression from Phase 0
- Add hide / show-hidden / gitignore-toggle bindings to the workspace panel
- Show .jaato/ in the workspace panel by default
- Phase 1: SDK feature parity — typed WS verbs + JaatoClient methods
- Phase 0: Migrate jaato-sdk events.py from @dataclass to pydantic
- Apply .gitignore filtering to sandbox path tracking
- Surface cgroup OOM-kill events as OTel attributes on tool spans
- Add cgroup.events reader for kernel-killed attribution
- Apply runtime_limits at the interactive_shell spawn layer
- Apply runtime_limits at the subprocess layer (CLI plugin)
- Wire runtime_limits profile field through to per-session cgroups
- Rename SandboxConfig to RuntimeLimits, drop network field
- Add per-session cgroup v2 runtime for resource limits
- SDK file staging: binary-framed StageFilesRequest for WS clients
- references: AppArmor reference fragments for confined WS sessions
- Intercept %<name> --help before model dispatch
- WS auth: default to ~/.jaato/ws.token, auto-create on first run
- Support --help flag for %prompt and /prompt commands
- Update WS transport client reference: add auth mechanism docs
- WS bearer-token auth (Option A): close the open-port default
- notebook: richer SyntaxError diagnostics + quote hint
- permission hook: don't clobber pending-prompt id from parallel auto-decisions
- services check_credentials: route through _resolve_credential too
- services auth: resolve pass://, vault://, etc. alongside env var names
- ParameterLocation: add body, formData, cookie for full OpenAPI coverage
- services: tiered lookup (workspace → user home), mirroring the rest of jaato
- AppArmor: skip for IPC sessions; fix thread restore-to-unconfined
- Rewind-with-hint: recover from max_tokens-truncated tool calls
- Render <j-code>/<j-table> in the TUI; drop per-client branching on the server
- References: references merge subcommand for knowledge-bundle consolidation
- References: knowledge bundles with per-bundle sidecars + reconcile
- References: move sidecar row ordering to embedding_config.json
- Surface masked credential-load errors in NIM, Anthropic OAuth, GitHub Models
- Zhipu AI auth: surface masked provider errors instead of "no credentials"
- Enrichment plugins: dedup per-session hints across tool calls
- Table formatter: wrap oversized rows to fit console width
- Cache hit rate: divide by total input, not just new (uncached) input
- Notebook bridge: inherit outer tool approval, no inner permission prompts
- TUI rendering: pass ClientType.value to formatters, not str(enum)
- signal_completion: typed payloads from profile-declared schema
- template: rename writeFileFromTemplate → renderTemplateToFile
- WS session.new: materialise inline staged_files into provisioned workspace
- session.new --no-instructions: partial base suppression (not full override)
- session.new: --instructions override, honest budget, lazy base instructions
- LM Studio: reuse loaded instance + discover live context length
- verify_auth: thread profile plugin_configs into providers; LM Studio drops reachability probe
- Template plugin: tag-coherent prompt/tool-result enrichment
- LM Studio provider + profile→provider config wiring
- AppArmor: allow memories/ folder layout, bump template version for cache invalidation
- Memory storage: split raw queue (folder) from curated store (single file)
- Memory: fetch by IDs + restructure hint to suggest a single call
- Extract tag-coherence matching into shared utility, apply to references
- Memory enrichment hint: show triggering tags only
- Memory indexer: sentence-scoped segments + size cap
- Memory indexer: paragraph-coherence matching for compound tags
- Memory: enrich tool results + index compound tags by sub-tokens
- Code block formatter: emit semantic <j-code> markup for web clients
- Fix: propagate client_type to lazily-created agent pipelines
- Rename table tags from nb- to j- prefix
- Table formatter: emit semantic <nb-table> markup for non-terminal clients
- Add agent_name parameter to create_headless_session
- AppArmor: allow read access to premium package directory
- Fix: register signal_completion on session directly, not as core tool
- Fix: don't unload session while model thread is still active
- Move signal_completion from plugin to core tool
- Fix: add missing ToolPlugin protocol methods to lifecycle plugin
- Add lifecycle plugin with signal_completion tool
- Fix: WS disconnect crash — _session_manager not on JaatoWSServer
- Extract shared subprocess runner from CLI plugin
- Add {{!command}} command substitution to prompt templates
- Fix: session env race condition between concurrent sessions
- Fix: make tool ID map suffix-transparent for :stream variants
- Permission timeout configurable per-client via ClientConfigRequest
- Bundle tool_id_mappings in SessionInfoEvent for guaranteed delivery
- Remove ID format examples from introspection parameter descriptions
- Fix: re-emit ToolIdRegistry after WS client registers tools
- Introspection: restore name alongside id, strengthen id-only params
- Fix: emit ToolIdRegistry during init AND on reconnect
- Fix: build ToolIdRegistry eagerly from tool schemas, not _reverse
- Fix: emit ToolIdRegistryEvent in emit_current_state only
- Introspection output: remove name field, model sees only IDs
- ToolIdRegistryEvent: server pushes ID→name mapping to clients
- Introspection output: include human-readable names alongside hash IDs
- Replace tool name strings with hash-derived IDs at provider boundary
- Memory plugin: configurable global storage path; auth: bearer debug logging
- SessionManager: add create_headless_session for daemon extensions
- Extract shared script loader from permission evaluator
- Memory indexer: exact-match only + min 2-tag overlap for enrichment
- Global memory tier: cross-session knowledge with quality curation
- Fix: strip auth headers on cross-domain redirects (httpx path)
- snapshot_workspace: remove unnecessary session pause
- AppArmor: actively unconfine thread before framework-level tools
- list_tools: drop category string parameter, index-only
- list_tools: add category_index parameter as integer alternative
- list_tools: build category enum dynamically from registry
- list_tools: show all tools in a category regardless of session profile
- list_tools: name missing plugins in category availability hints
- list_tools: show per-category availability based on session plugins
- list_tools: show registered categories even when no tools are loaded
- Fix UnboundLocalError in list_tools category validation
- list_tools: report unknown categories instead of returning empty list
- WS: read category descriptions from tools.register_client message
- Dynamic tool category descriptions via PluginRegistry
- Fork-replay primitives: 5 general-purpose capabilities for session manipulation
- Expose session fork primitives + registry protocol-mismatch warning
- Reliability: honor plugin_configs.reliability from profile
- Resilience hardening: Tier 3 (external service resilience)
- Resilience hardening: Tier 1 (storage) + Tier 2 (plugin lifecycle)
- Normalize None defaults and Python booleans in prompt substitution
- Apply frontmatter param defaults during prompt substitution
- Pass user-supplied args through %prompt-name expansion
- Fix per-turn placeholder leak in agent system instructions
- Dedup and default-aware missing parameters in prompt_library
- Add telemetry for the GC ↔ cache plugin coordination
- Disable code_block_formatter line truncation by default
- Allow ML model caches (~/.cache/huggingface, ~/.cache/torch) in AppArmor profile
- Allow Claude Code skills and commands dirs in AppArmor profile
- Fix AppArmor confinement leak; harden prompt_library against unreadable sources
- Confine tool execution by default; opt out via TRAIT_FRAMEWORK_LEVEL
- Allow user-global jaato config in AppArmor profile; fix subagent truncation inheritance
- Disable line truncation in code_block_formatter for non-terminal clients
- Allow read access to jaato source tree in AppArmor profile
- Fix sandbox false-positive on WS-provisioned workspaces under ~/.jaato/
- Remove dead aa-exec wrapping path; thread-level confinement is canonical
- Skip aa-exec wrapping when thread-level AppArmor confinement is active
- Allow both /tmp/jaato-<sid>-* and /tmp/jaato-<sid>/* in AppArmor profile
- Fix AppArmor profile blocking agent's own workspace
- Add thread-level AppArmor confinement for in-process file I/O tools
- Add fork_ask, proactive tool result cap, server-side % dispatch, and structured auth errors
- Fix: run GC check between tool calls in agentic mode
- Add diagnostic logging to GC pre-send check
- Fix: read cumulative input_tokens from message_delta per Anthropic spec
- Fix: save_to downloads binary data correctly (raw bytes)
- Fix: enable HTTP redirect following in call_service
- Add save_to parameter to call_service for file downloads
- Include comment in PermissionResolvedEvent for WS clients
- Add ALLOW_COMMENT to permission channels (yc: prefix)
- Add ALLOW_WITH_COMMENT to permission evaluator contract
- Fix: set daemon_session_id before set_agent_context
- Fix: inject session_id into permission context for evaluators
- Fix: store workspace_path in permission plugin for evaluator context
- Fix: use session manager session_id for AppArmor profiles
- Fix: don't create .jaato/sessions at daemon startup from cwd
- Remove debug logging for daemon plugin workspace injection
- Add debug logging for daemon plugin workspace injection
- Fix: inject client workspace into daemon plugins at command execution
- Fix: initialize _workspace_path in __init__ for all auth plugins
- Fix: pass workspace_path to all auth plugins for credential storage
- Add typed ZhipuAIRateLimitError and retry classification
- Fix Z.AI context limits: add glm-5-turbo, update default to 200K
- Fix: inject workspace_path into permission plugin init config
- Fix unreachable code in memory plugin get_config_schema()
- Remove channel_type/channel_config from plugin config schemas
- Migrate plugin config schemas from PluginSetting to JSON Schema
- Add turn_index and model_preamble to evaluator context
- Run evaluators even for pre-approved tools
- Extend permission evaluators with full scoped decisions
- Add runtime-injectable permission evaluators
- Implement profile inheritance with inherits field
- Fix Z.AI model discovery URL and add cross-provider list_provider_models()
- Fix AppArmor profile name mismatch in daemon session hook
- Remove dead auto_approved field from SubagentProfile
- Flush pending client tools after session.attach (not just session.new)
- Propagate daemon session ID into all OTel spans as jaato.session_id
- Add config introspection to GC plugins and expose them on daemon context
- Expose plugin_registry on daemon extension context
- Document get_config_schema() in plugin implementation guide
- Add introspectable plugin settings via PluginSetting and get_config_schema()
- Expose available_plugins on daemon extension context
- Cache entry point lookup in embedding subsystem discovery
- Fix AppArmor session hook: check self._apparmor at execution time
- Fix sandbox_mode: use session hook and run hooks after Session creation
- Add debug logging for sandbox_mode session lookup
- Fix sandbox_mode not appearing in session.info event
- Include sandbox_mode in session.info event
- Fix AppArmor profile loading: use sudo for apparmor_parser
- Fix AppArmor cache permission error and align docs with implementation
- Add TUI installer and restructure dependencies into optional extras
- Extract embedding subsystem behind jaato.embedding entry point protocol
- Complete agent/profile split: SDK, TUI, and deprecation warning
- Split agent (prompt) from profile (runtime config)
- Remove icon and icon_name from profiles
- Add anti-hallucinated-constraints rule to framework instructions
- Preserve running subagents during plugin shutdown/re-init
- Fix client tool execution during WS disconnection
- Stop PARENT messages from interrupting subagent streaming
- Expose EventBus from JaatoServer for daemon extensions
- Pass client_id to WS message handler callbacks
- Add user identity tracking for sessions and WS message handlers
- Include session_id in session hook callback
- Add extensible WS message handler registration
- Emit events.subscribed notification for external event subscriptions
- Add event.external WS handler for client-to-agent event injection
- Include cancellation reason in [Generation cancelled] messages
- Fix session span parenting: all agents share one root session span
- Add session and agent spans for full trace tree hierarchy
- Allow env var references in command sanitizer
- Load template index from disk independently of references plugin
- Use custom_name from spawn_subagent as agent display name
- Add TLS support to WebSocket server
- Fix core executor lookup in all 3 ai_tool_runner code paths
- Fix: look up core tool executors in ai_tool_runner fallback

---

# jaato-server

Jaato Server — LLM tool orchestration runtime and daemon.

See the [project README](../README.md) for full documentation.
