Skip to content

Ari Assistant

Status: Current | Last reviewed: 2026-10-20

Use the separate Ari app to validate an assistant experience against published Poppy agents. Read this page when operating the app, reviewing its trust boundaries, or updating its OpenMuse engine.

Component Location
Browser app and backend apps/assistant
Vanguard address https://assistant.vanguard.dev.trueserve.deloitte.com
Process assistant, loopback HTTP port 3035
Runtime Node 22, Hono, React, OpenMuse TanStack engine
Storage Separate trueserve_assistant PostgreSQL database
Authentication Existing Studio users, active tenant membership and OAuth scopes
Company adapter Separate Poppy Company gateway, port 3036

Desktop and phone presentation

Phone view applies to the entire signed-in app. It uses the canonical PhoneFrame from shared/phone-emulator, with Ari already open. The surrounding Studio-style sidebar, top bar and chat context panel are not mounted. Conversations, Connections, Approvals and Settings use in-app navigation. Ari chat history is searchable; Company messages retain their own list and direct-message controls. Hash routes preserve the selected screen and conversation across reloads, and browser Back restores the previous screen.

On a desktop viewport the shared handset scales to fit. At 600px and below, the same app fills the available screen without a second device frame. Settings → Desktop view returns to the full workspace. Protocol lab, HTTP activity, discovery JSON, client-profile selection, operation IDs and manual operation inspection are desktop tools. Phone approvals still show the exact business terms and proposal revision.

The standalone build imports the shared frame source and resolves its React imports to the Assistant's React instance. It does not import Studio or the emulator's call runtime. Ari's stylesheet is loaded inside the frame's shadow root. Build fingerprints keep the outer page and shadow-root stylesheet on the same version after an update.

Add a connection

Connections uses a URL entry and a live catalog from GET /api/studio-exposures. The catalog refreshes when setup opens, when the page becomes visible, every minute while mounted, and on explicit refresh. Loading, empty and unavailable states remain distinct.

The setup flow posts {url, profileId} to POST /api/companies/setup and reads SSE setup events:

Stage Completed work
finding Setup started; discovery and issuer validation are in progress
connecting Discovery is verified; session and DPoP token setup are in progress
complete A usable session exists and the Company connection is saved
error Setup could not finish; the UI keeps the address for retry

The server validates the owner, origin and profile, and performs all external requests through the existing safe HTTP client. Tokens and keys never appear in setup events. A new Company is saved only after its session succeeds; failed setup removes its provisional credentials. Serializing setup per owner/profile/discovery URL lets retries reuse the existing connection when its issuer matches. Company account consent remains a separate owner action. Its sign-in callback returns to Connections in the saved desktop or phone display.

Request and identity boundaries

The browser receives an opaque HttpOnly session cookie. Studio sign-in uses dynamic client registration, S256 PKCE, a browser-bound state value, exact callback matching and issuer verification. The grant requests agents:read and agents:debug, which correspond to the existing Run Agents permission. It does not request write or publication authority.

Every workspace API request rechecks identity and tenant membership through Studio's /api/v1/management/identity. Model tools and protocol runs also check authorization between steps. Logout deletes the local session, revokes the Studio grant and stops that owner's running assistant turn. Already accepted Company actions are not cancelled by signing out.

The server derives record ownership from tenant UUID:user UUID; callers cannot choose another owner. Each user has separate connections, chats, profiles, approvals, traces and appearance within each tenant. Studio tokens, Company tokens and private signing keys are encrypted with purpose/owner-bound AES-GCM. Session handles and browser login state are stored hashed.

The default model path is:

Browser → Ari backend → Studio tenant model proxy → configured OpenAI integration
                    → Poppy Company session → Company conversation or operation

The OpenMuse engine receives only the owner's selected Company and its non-secret discovery. Its tools can contact that Company, read conversations, read an operation and request an approval card. No model tool can confirm an operation, publish an agent or claim sender=human. Company content is untrusted input. AG-UI state events do not mutate application authority.

Studio retains provider credentials. Its model proxy requires agents:debug, resolves integrations under the authenticated tenant, applies provider policy, restricts model IDs, caps input/output and disallows provider-hosted tools or stored-response references. An operator can opt into environment credentials for a separate deployment; that changes model billing from tenant-specific to service-wide.

Poppy behavior

Area Implemented behavior
Discovery Poppy 0.2; verifies serving domain and issuer poppy_domains; limited discovery redirects
Network HTTPS; public DNS addresses pinned to the socket; no credential-bearing redirects; bounded response sizes/timeouts
Personal Agent identity Public client metadata and JWKS per immutable profile; ES256 client/session assertions
Company sessions Separate DPoP key; issuer audience, fresh JWT IDs, nonce challenges, token hash and resource binding
Account connection Direct Sign-In with PKCE, owner/state/issuer checks and existing session binding; account grant revocation
Conversations Acceptance-only 201/202, paginated JSON events, immutable replay, direct children, handoff and close
Interrupted requests Durable original message IDs and outbox; explicit retry after unknown delivery
Expired cursors Reload available history, keep locally retained events and display a history-gap notice
Operations Display exact terms/revision, owner-only confirm/cancel, changed-term rejection, duplicate-click claim, status reconciliation
Client profiles Core-only or Operations v1; profiles keep their public identity when appearance changes

The client retains the most recent 2,000 events per conversation. The gateway's authoritative ledger retains its full event history. The inspector redacts credentials but still contains test messages and Company payloads; use synthetic data and treat database backups as application data.

The browser receives app-state notifications over SSE. Company conversations use JSON polling; these are distinct transports. A model turn waits for a working Company within its bounded turn, and the selected Company conversation polls while visible. The model cannot promise a later background turn.

Owner actions refresh saved workspace state after either a successful or failed response. A failed approval decision also notifies other open sessions: a lost confirmation response must show the persisted unknown outcome and Check status, rather than leaving a stale confirming card.

Protocol lab

Each run records its Company, client profile, discovery snapshot, timestamps and individual pass/fail/not-exercised results. It tests signed sessions, key binding, event replay, duplicate message IDs, changed-payload conflicts, parent locks and idempotent close. Test conversations are closed at the end.

The run does not automatically consent to Company account access, confirm business operations, or claim a real human joined. Those scenarios appear as Not exercised. The approval UI and independent fixture tests cover Operations behavior separately. Before/after comparison and JSON export retain the distinction.

The gateway includes x-trueserve.agent_version as a nonstandard discovery annotation. It is captured in run snapshots to identify the reviewed version. External Companies need not provide this field.

Operations

See apps/assistant/README.md for complete provisioning and environment settings. Both new services are optional and exit without starting when their private local config is absent.

Keep the app database and encryption key together when backing up or restoring. Startup takes an exclusive database lease, marks unfinished chat/test turns interrupted and marks interrupted confirmations unknown. It never confirms again merely because a process restarted. The first release supports one Assistant process per application database.

On Vanguard, the small Procfiles can coexist with the current city stack:

overmind status -s .overmind-assistant.sock
overmind restart assistant -s .overmind-assistant.sock
overmind status -s .overmind-poppy.sock

The nginx template includes both new hosts, disables OAuth callback access logs, limits request bodies and disables buffering for streams. The host certificate must cover assistant.<city> and each poppy-<id>.<city> hostname.

Deployment manifests for official Dev/QA/production are not included in this pilot. Before expanding, add managed secret storage, deliberate retention, usage reporting, deployment/rollback automation and a distributed worker lease if multiple instances are required.

Upgrades and checks

The engine source, commit, hash, MIT license and local changes live in apps/assistant/vendor/openmuse. Upgrade that source and its compatible package versions together. Run type checking, HTTP/security tests, the independent browser fixture, and the real hosted sandbox check. Re-run against a second Company implementation before claiming interoperability beyond the tested profile.

From apps/assistant, run:

pnpm typecheck
pnpm test
pnpm build
pnpm test:browser

For the real Vanguard sandbox, run bash ../../.devcontainer/scripts/with-env.sh node --import tsx scripts/prepare-assistant-validation.ts from apps/ai-manager, then pnpm test:hosted from apps/assistant. Preparation creates a short-lived Studio validation session in a private temporary file. The browser test signs out; remove /tmp/assistant-validation-session.json afterwards.

Company Device Sign-In, SSE, OpenAPI/MCP execution, browser continuity and standing permissions are not implemented. The browser still shows the Company's advertisements in desktop view so a tester can identify the difference.

See also