Skip to content
ochat
Search documentation

Use quotes for an exact phrase.

Search by topic, command, or code identifier.

    GitHub ↗

    Connect an HTTP client

    Use the TUI, gateway, or raw HTTP with private credentials and a restricted observer.

    View Markdown source ↗

    Use an authenticated loopback listener, establish a logical connection, and observe its permitted live updates.

    Complete installation, private example setup, and the stdio protocol walkthrough. Run checkout commands from the repository root with its active opam environment. Terminal B and later terminals must set OCHAT_DEMO to Terminal A’s absolute path. The local listener is plain HTTP on loopback, not public HTTPS. Discovery/attachment use no model calls; sending a chat request requires credentials in the daemon and incurs charges.

    Read the current provider TLS and permission boundaries before model work or deployment. Build troubleshooting includes the Apple Silicon/OpenBLAS setup path.

    Prepare the private examples. Stop any Unix-only daemon using that root, then in Terminal A:

    Terminal window
    dune exec bin/ochat_agent_server.exe -- -config "$OCHAT_DEMO/http.sexp" -validate-only
    dune exec bin/ochat_agent_server.exe -- -config "$OCHAT_DEMO/http.sexp"

    This binds 127.0.0.1:8787 and uses generated hashed credentials. If the port is occupied, choose another port in the private config and all client URIs; do not terminate an unrelated process. Keep admin.token and observer.token private.

    Terminal B can create a durable session directly through the TUI:

    Terminal window
    dune exec bin/chat_tui.exe -- --no-config --connect http://127.0.0.1:8787 \
    --bearer-token-file "$OCHAT_DEMO/admin.token" --new-daemon-session \
    --prompt hello --workspace project --detached

    Or use the raw-envelope gateway over HTTP:

    Terminal window
    dune exec bin/ochat_agent_stdio.exe -- --connect http://127.0.0.1:8787 \
    --bearer-token-file "$OCHAT_DEMO/admin.token"

    Initialize using discover.ndjson, then list/attach as in the stdio tutorial. The transport adapter handles HTTP connection IDs and the connection notification SSE reader. The compiled docs_example client demonstrates the same embedding API.

    With curl installed, the setup helper supplies a validated handshake and a private curl credential config. Do not use verbose/header tracing with secrets:

    Terminal window
    curl --fail-with-body --silent --show-error --config "$OCHAT_DEMO/admin.curl" \
    -D "$OCHAT_DEMO/initialize.headers" \
    -H 'Content-Type: application/json' -H 'ochat-protocol-version: 1.0' \
    --data-binary "@$OCHAT_DEMO/initialize.json" http://127.0.0.1:8787/v1/rpc
    OCHAT_CONNECTION=$(awk 'tolower($1)=="ochat-connection-id:" {gsub("\r", "", $2); print $2}' "$OCHAT_DEMO/initialize.headers")
    curl --fail-with-body --silent --show-error --config "$OCHAT_DEMO/admin.curl" \
    -H 'Content-Type: application/json' -H 'ochat-protocol-version: 1.0' \
    -H "ochat-connection-id: $OCHAT_CONNECTION" \
    --data '{"jsonrpc":"2.0","id":"sessions","method":"session.list","params":{"limit":20}}' \
    http://127.0.0.1:8787/v1/rpc

    In another terminal (with the same variables), observe connection notifications:

    Terminal window
    curl --no-buffer --silent --show-error --config "$OCHAT_DEMO/admin.curl" \
    -H "ochat-connection-id: $OCHAT_CONNECTION" http://127.0.0.1:8787/v1/events

    That stream stays open until interrupted/closed; it may contain no session updates until this logical connection subscribes through create/attach. For an independent session observer after setting OCHAT_SESSION from the session list:

    Terminal window
    curl --fail-with-body --silent --show-error --config "$OCHAT_DEMO/observer.curl" \
    "http://127.0.0.1:8787/v1/sessions/$OCHAT_SESSION/snapshot"

    Read latest_event_sequence from the snapshot into OCHAT_SEQUENCE, then:

    Terminal window
    curl --no-buffer --silent --show-error --config "$OCHAT_DEMO/observer.curl" \
    "http://127.0.0.1:8787/v1/sessions/$OCHAT_SESSION/events?after_sequence=$OCHAT_SEQUENCE"

    After interrupting streams, close the operator logical connection deliberately:

    Terminal window
    curl --fail-with-body --silent --show-error --config "$OCHAT_DEMO/admin.curl" \
    -X DELETE -H "ochat-connection-id: $OCHAT_CONNECTION" http://127.0.0.1:8787/v1/connection

    For an implementation independent of Ochat’s client library:

    1. Load the raw token from its private file without logging it.
    2. POST the fixture’s initialization envelope to /v1/rpc with bearer auth, JSON content type, and ochat-protocol-version: 1.0.
    3. Capture ochat-connection-id from the response headers. Supply it on subsequent RPCs, /v1/events, and DELETE /v1/connection.
    4. Open /v1/events for notifications or use the per-session snapshot/event routes for a separate read-only projection. Do not give connection notifications a durable replay guarantee they do not have.
    5. Discover prompt/workspace IDs, create or attach a session, and retain attachment IDs for mutations. Follow the protocol reference, not the friendly catalog names used by TUI convenience flags.
    6. Correlate response IDs while receiving events. A message acknowledgement can say deferred; wait for terminal operation/history events to report completion.

    The complete route/header and SSE reference specifies error handling, body/batch limits, and payload boundaries. Implement SSE parsing at frame boundaries, not network chunks. Use a library that supports incremental streaming rather than reading the entire SSE body before processing it.

    Quit the writer TUI, list sessions with its operator token, and assign the returned ID to OCHAT_SESSION. In a second terminal:

    Terminal window
    dune exec bin/chat_tui.exe -- --no-config --connect http://127.0.0.1:8787 \
    --bearer-token-file "$OCHAT_DEMO/observer.token" --session "$OCHAT_SESSION" --read-only

    The observer token has only transcript-read scope. Finalized transcript updates are visible; protected tool/permission/provider-delta detail is not. Attempts to write are rejected. A separate read-only attachment with the admin token would still have that token’s broader read scopes.

    The generated operator and observer tokens represent the same principal with different scopes. A token for a different principal cannot view this session merely by holding transcript-read scope. Regenerate fixtures created by the old helper that assigned separate principals. Each TUI initializes its own HTTP connection; do not pass an operator connection ID to the restricted observer.

    For a raw session subscriber, remember the latest durable sequence, disconnect, then request events after that sequence. On snapshot_required, fetch/replace the snapshot and retry after its new sequence. Do not reuse a connection ID after server restart; initialize again. Unsent editor drafts belong to the client and should not be resent automatically as new mutations during reconnect.

    Close logical connections deliberately and quit clients before Ctrl+C in Terminal A. Detached sessions remain in the private store for the next startup. No public listener or real-model request is required to test discovery/attachment.

    Checkpoint, troubleshooting, and next step

    Section titled “Checkpoint, troubleshooting, and next step”

    Success means an initialized RPC returns its matching response, and an authorized observer receives permitted transcript updates after a session actually produces them. An idle SSE stream is normal without events; an acknowledgement is not completed model work. For 401/403 errors, check the private token file, principal, scopes, and whether the logical connection was initialized with that credential. On restart initialize again. For a port conflict choose another port consistently. Close streams/connections, quit clients, and stop Terminal A before archiving/removing the private demo root and its credentials. The durable store remains until removed. Next, read HTTP transport contracts and permissions.

    View source · Protocol discovery2 files

    Complete source files. Open a filename to read it here.

    discover.ndjsonStart here
    {"jsonrpc":"2.0","id":"initialize","method":"protocol.initialize","params":{"implementation":{"name":"tutorial","version":"1"},"protocol_min":{"major":1,"minor":0},"protocol_max":{"major":1,"minor":0},"features":[],"event_encodings":["json"],"max_inbound_event_bytes":16777216}}
    {"jsonrpc":"2.0","id":"info","method":"server.info","params":{}}
    {"jsonrpc":"2.0","id":"prompts","method":"prompt.list","params":{"limit":20}}
    {"jsonrpc":"2.0","id":"workspaces","method":"workspace.list","params":{"limit":20}}
    {"jsonrpc":"2.0","id":"sessions","method":"session.list","params":{"limit":20}}
    

    Link to this fileDownload this file

    LICENSE.txtnotice
    MIT License
    
    Copyright (c) 2025 
    
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:
    
    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.

    Link to this fileDownload this file