How each client connects to a running UNITARES governance server. Adapters are a convenience layer — the server is the source of truth and the client stays thin. For env-var configuration see the Configuration section of the README.
This repo owns Claude/Codex plugin packaging, hook scripts, shared guidance, and
the generic identity sidecar. The Hermes-native lifecycle binding does not
live here; it lives in unitares-host-adapter
as unitares_host_adapter.bindings.hermes and is loaded by a thin Hermes user
plugin at ~/.hermes/plugins/unitares.
A direct Hermes MCP server entry is a third surface: it exposes callable UNITARES tools, but it does not add lazy onboarding or automatic turn check-ins unless the Hermes plugin/host-adapter layer is also enabled.
The current Claude adapter includes session-start, pre-edit, post-edit, and session-end hooks. Those hooks should be treated as an adapter convenience, not the canonical governance policy. In particular, frequent file writes should not automatically be interpreted as meaningful governance events.
The pre-edit hook acquires a BEAM file lease before Edit/Write/MultiEdit. Missing lease-plane configuration fails open by default, while real held_by_other contention blocks the edit with a visible explanation. Post-edit releases the just-edited file lease immediately; session-end remains a best-effort cleanup path for any lease that survived an interrupted edit.
The session-start hook remains read-only: it tells the agent to call start_session(force_new=true) before substantive work. If the agent has not onboarded by the end of the turn, post-stop uses scripts/onboard_helper.py to lazily mint a fresh, slot-scoped identity and then emits the normal turn_stop summary under that identity. Set UNITARES_AUTO_ONBOARD=off or legacy UNITARES_DISABLE_AUTO_ONBOARD=1 to fall back to identity-free floor observations for un-onboarded sessions.
For the full Claude check-in trigger contract, see check-ins.md.
Codex and ChatGPT support should stay minimal and explicit:
- package shared skills through
.codex-plugin/plugin.json - document manual command flows for agents that can use them
- treat
.unitares/session-<slot>.jsonas the neutral local continuity cache; flat.unitares/session.jsonis legacy/read-only - use
scripts/session_cache.pyas the shared cache helper across adapters - avoid client-specific auto-checkin behavior until there is a Codex-native reason to add it
If you want adapter-like onboarding/check-in behavior from Codex, run the sidecar (below). The full Codex/ChatGPT quickstart lives in CODEX_START.md.
For clients without lifecycle hooks, run the local identity sidecar and send governance REST tool calls through it:
python3 scripts/identity_sidecar.py \
--server-url http://localhost:8767 \
--workspace "$PWD" \
--slot codex-local \
--port 8768Phase 1 is a dependency-free sidecar, not a full streamable-MCP/SSE
implementation. It wraps REST /v1/tools/call and minimal JSON-RPC MCP
/mcp/ requests, lazily onboards a slot when needed, injects
client_session_id into attribution-relevant governance calls, forces
force_new=true for bare onboard / start_session, stamps the slot cache
after check-ins, and exposes GET /audit. Useful endpoints:
GET http://127.0.0.1:8768/client-config?slot=codex-localfor a generated MCP/client snippetPOST http://127.0.0.1:8768/v1/tools/callwith{"name": "...", "arguments": {...}}POST http://127.0.0.1:8768/mcp/for JSON-RPC MCP requests;tools/callis intercepted and other JSON requests pass throughPOST http://127.0.0.1:8768/turn/checkinwithresponse_text,complexity, andconfidencePOST http://127.0.0.1:8768/turn/stopfor an end-of-turn check-inGET http://127.0.0.1:8768/audit?log_tail=200for bounded local cache/log contract findings
Use X-UNITARES-Slot or top-level {"slot": "..."} when one sidecar serves
multiple clients. Without an explicit slot, the sidecar uses a workspace-derived
default slot.
The sidecar belongs in this repo while it remains a generic client facade. It is integration code: local cache management, lifecycle convenience, redaction, and REST/MCP proxying. The UNITARES server repo remains the source of truth for identity semantics, governance policy, storage, and tool schemas.
Do not create a separate sidecar repo just to support local models. Local and
non-frontier model runners should route through the sidecar when they cannot
load a richer plugin, because the sidecar keeps process identity out of prompt
context and normalizes the model-visible response. A separate repo becomes
worth considering only if the sidecar grows independent packaging, nontrivial
runtime dependencies, or host-specific lifecycle bindings comparable to
unitares-host-adapter.
Raw direct MCP/REST remains available for advanced clients and operator debugging. If a client uses raw direct calls in normal operation, its runner must own the same responsibilities the sidecar owns here: private session retention, identity injection on write calls, no proof material in prompts/logs, and check-ins after meaningful work.
For clients that accept a URL MCP server, point them at
http://127.0.0.1:8768/mcp/ only when they use JSON request/response MCP. The
generated GET /client-config response includes the URL, X-UNITARES-Slot
header, and a minimal mcpServers snippet. If a client requires streamable
HTTP/SSE semantics, use the upstream governance MCP endpoint until the sidecar
grows that transport path.