5.9 KiB
5.9 KiB
Profile Isolation Implementation Status
Purpose
This file is the changelog-style bridge between the design docs in this folder and the code that already landed. Use it when you need to answer three questions quickly:
- What isolation work is already implemented?
- Which code paths enforce it?
- Which follow-up gaps still need explicit review?
Completed phases
Phase 1 — Prompt and profile layering
Implemented:
- layered prompt assembly for system / principal / session ordering
- shared knowledge prompt block with separate budget and doc pointers
- principal-aware profile resolution helpers
Primary files:
agent/prompt_builder.pyagent/system_prompt.pyagent/shared_knowledge.pyagent/agent_init.pygateway/principal_profiles.pyhermes_cli/config.py
Phase 2 — Session, dashboard, and memory ownership gates
Implemented:
- principal-aware session visibility in dashboard routes
- owner-gated session detail / export / descendant access
- principal-scoped remote durable memory writes
- principal-aware
session_searchprofile access filtering
Primary files:
hermes_cli/web_server.pytools/memory_tool.pytools/session_search_tool.pygateway/platforms/api_server.py
Phase 3 — Verified-identity routing and managed-download ownership
Implemented:
- verified identity carried into API-server session binding
- principal-aware managed-download owner metadata
- owner-bound managed downloads rejected outside the matching request scope
Primary files:
gateway/platforms/api_server.pyhermes_cli/managed_downloads.pyhermes_cli/web_server.py
Phase 4 — API response-chain and session CRUD isolation
Implemented:
api_serversession CRUD / message / fork / chat endpoints now resolve the verified caller first and then operate inside the matching principal profile scope- response snapshots used by
previous_response_id, conversation-name chaining, andGET/DELETE /v1/responses/{id}now live in a per-profileresponse_store.db - streaming and non-streaming responses share the same principal-scoped response-store behavior
/v1/runsnow resolvesprevious_response_idfrom the active principal profile instead of a process-global store- a lazy compatibility proxy preserves
adapter._response_storecall sites in tests without opening SQLite on every adapter construction
Primary files:
gateway/platforms/api_server.py
Phase 5 — Download-link mode control
Implemented:
- managed downloads now support explicit
link_modeselection privatemode keepsowner_metadatabound to the linkpublicmode stripsowner_metadatawhile preserving the existing expiry policyapi_serverrequest bodies now acceptdownload_link_modeand return machine-readablehermes.download_link_mode*metadata so callers can prompt for private vs public link behavior/v1/responsesnon-streaming payloads now keepresponse.output[*]aligned with the rewritten managed-download URL instead of exposing a host-local artifact path in the assistant message item/v1/responsesstreaming terminal events now carry the same managed-download rewrite andhermes.download_link_modemetadata as the non-streaming path- live streaming delta paths now hold back split local file-path prefixes and rewrite them before delivery instead of briefly exposing
/Users/...orC:\...during SSE streaming - the OpenWebUI runs proxy now accepts
download_link_mode, forwards it upstream, and rewrites local artifact paths using owner-aware private/public managed-download selection instead of always minting public links
Primary files:
hermes_cli/managed_downloads.pytests/hermes_cli/test_managed_downloads.pygateway/platforms/api_server.pytests/gateway/test_api_server.pytests/gateway/test_session_api.py/Users/hermes/.hermes/scripts/openwebui_runs_proxy.pytests/gateway/test_openwebui_runs_proxy_handoff.py
Verified tests already exercised for this workstream
tests/agent/test_system_prompt_principal_precedence.pytests/agent/test_system_prompt_shared_knowledge.pytests/gateway/test_principal_profile_routing_phase1.pytests/gateway/test_principal_profile_runtime_phase2.pytests/gateway/test_api_server_session_ownership.pytests/hermes_cli/test_web_server_session_access.pytests/gateway/test_api_server.py -k 'ResponsesEndpoint or ResponsesStreaming or Truncation or ConversationParameter'tests/gateway/test_multiplex_api_server_routing.pytests/hermes_cli/test_managed_downloads.py
Remaining follow-up review items
These are not known regressions, but they remain explicit review targets whenever this isolation layer changes again:
- artifact-rewrite call sites outside
api_serverthat may still default to public links without a caller-selected mode - gateway UX hooks that should ask the user whether a link should stay owner-bound or become public
- any future response-chain storage outside
response_store.db - non-API file-delivery paths that may need the same principal-aware mode selection contract
Operational finding from live runtime inspection
- the current macOS LaunchAgent
~/Library/LaunchAgents/ai.hermes.gateway.plistwas found runninggateway run --replace launchctl print gui/$(id -u)/ai.hermes.gatewayshowed repeated restarts (runs=41,forks=2400, last terminating signalKilled: 9) while the service was still healthy- for a long-lived supervised LaunchAgent,
--replaceshould be removed and reserved for explicit operator takeover flows instead of steady-state service startup - see
restart-recovery-runbook.mdfor the safe reload / health-check sequence before applying that launchd change
Current invariant
If a request is authenticated as principal A, then:
- it must read and write only principal A's session store and response store,
- it must not resolve principal B's response chain,
- and any owner-bound download minted from that request must remain inaccessible to principal B.