Skip to content

Live agent connections

Connect the same context-and-response loop wherever your agents work. By default, the host first assesses the current request in its conversation, then chooses whether to answer from that exchange, retrieve missing evidence, or clarify. This intake does not search the vault or refresh workspace policy. An evidence decision reads the current Planisphere workspace policy and selected local originals through Planisphere and Grapheine. Changed source bytes invalidate earlier evidence; a changed policy prevents reuse of an earlier evidence packet and can request a bounded response correction.

On Connections, select Codex, Claude Code, OpenAI Agents SDK, or Custom agent harness, then copy Connect live context into the agent that maintains that environment. Existing activity recording remains available below it and is preserved by the installer.

Signing in establishes workspace access. The synchronous loop also needs a local source route, an installed adapter, and host activation. A browser login cannot install scripts on a different machine. Sources are not copied across devices: each host needs access to the explicitly selected original vault. This is fresh policy and source observation at turn boundaries, not a distributed transaction or a guarantee that nothing changes afterward.

Install the common bundle

Python 3.10+ on macOS or Linux is supported. OpenAI Agents SDK 0.22.2 is the tested SDK version. Download and inspect the agent bundle, then extract its files into a private local tools directory. No Git repository access or unpublished package is required.

Reuse the private connection file made by your existing Planisphere connector. It contains base_url, api_key, and system_id. For a new connection, obtain a workspace key from Keys and save it locally using a masked terminal prompt or your service's secret environment; do not place a key in chat, shell arguments, or a repository. Use the intended HTTPS API origin. Keep files owner-only.

Create a private settings file. Replace these example paths with the actual approved paths for this host; the registered vault name and root are explicit:

{
  "connection": "/private/planisphere/connection.json",
  "policy": "/workspace/AGENTS.md",
  "state_root": "/private/planisphere/turns",
  "read_backend": "planisphere",
  "retrieval_mode": "host_assessed",
  "grapheine": "/home/owner/.local/bin/grapheine",
  "routes": [{
    "project": "/workspace/project",
    "vault": "project-notes",
    "root": "/workspace/notes",
    "excluded_paths": []
  }],
  "excluded_roots": []
}

Select the policy that actually governs the host. A Codex-specific instruction file is not automatically authority over another agent. Workspace policy is supplied with its revision and publisher as data to reconcile with governing instructions; it cannot grant tool permissions, choose a different vault, or install remote code. Use the exact native Planisphere vault route and preserve its exclusions. retrieval_mode: "host_assessed" is the default; the explicit automatic compatibility mode retains the older heuristic retrieval path and does not provide the assessment-before-search behavior described below.

From the extracted bundle:

python3 planisphere_connect.py install --host claude-code \
  --settings /private/planisphere/settings.json \
  --destination /private/planisphere/agents \
  --host-home /home/owner/.claude

Use --host codex and the intended .codex directory for Codex. Use --host openai-agents or --host custom without --host-home for application bundles. The installer authenticates a fresh policy read before changing host settings, enables sync_policy, and prints the versioned bundle directory. It backs up host configuration and replaces only hooks it owns. It never changes hook trust or model permissions. Review new hooks in the host's normal interface and start or reload the host normally. Claude Code must supply its native prompt_id; older hosts report an unchecked turn instead of guessing.

Application lifecycle

Add the printed versioned bundle directory to your application's Python import path. The default mode requires an application-owned context_resolver before the answer run. It may be a synchronous or asynchronous callable using the application's existing reasoning model and conversation. Planisphere does not select a provider, credentials or a model for this decision.

For an existing non-streaming Agents SDK workflow, replace its outer Runner.run call while keeping the agent, tools and run configuration. In this example, resolve_context is the callable supplied by your application using the contract below; it is not a function bundled with Planisphere.

from planisphere_harness import OpenAIAgentHarness

harness = OpenAIAgentHarness("/private/planisphere/agents/VERSION/settings.json")
turn = await harness.run(
    agent, user_prompt, session_id=conversation_id, turn_id=request_id,
    cwd=project_root, run_config=run_config,
    context_resolver=resolve_context,
)
response = turn.result.final_output
review = turn.review

Resolver contract

The callable receives the parsed context packet. When its status is awaiting_interpretation, inspect intake.current_input, intake.conversation, intake.conversation_coverage and the declared task. Decide what the current request means before forming a search query. Missing history remains unknown; a previous declared task does not establish the current request's subject. Return a decision dictionary with these fields:

Field Meaning
decision_id A nonempty identifier for this decision; reuse it only for an exact retry.
outcome conversation, evidence or clarify.
question The current request as understood in its conversation.
rationale Why that outcome follows from the observed exchange.
basis One to nine objects, each containing only message_id and quote.
gap and query Required, nonempty strings for evidence; omit them for the other outcomes.

For each basis item, use intake.current_input.message_id or an id from intake.conversation. Its quote must be an exact, nonempty substring of that message's presented content. The current content may have voice transport wrappers removed; quote the presented content, not the raw wrapper. A decision must cite at least one such message. The adapter binds action, intake_id and expected_revision itself; the resolver must not override those bindings. These checks establish attribution and freshness, not semantic correctness, permission or acceptance of an action.

conversation and clarify perform no vault retrieval. Compose the answer or necessary clarification from the resulting packet and the actual conversation. An evidence decision starts scoped retrieval. For subsequent evidence packets, the resolver returns None when the evidence is sufficient, or {"gap": "specific missing evidence", "query": "targeted search"} for a bounded refinement. The adapter allows at most two refinements. Inspect incomplete coverage and retained gaps before claiming a supported answer; successful commands alone do not establish that the evidence answers the question.

Display remaining issues and unchecked notices alongside the response. The adapter preserves the existing SDK filter, hooks, session and completed tool results. One repair can make a second SDK run and incur additional model calls; it runs context provisioning again. Approval interruptions return without repair. Streaming is not supported; server-managed histories require repair=False and application-owned continuation. Completed tool effects cannot be rolled back by a response check.

Custom Python host

Use the same resolver before composing the answer:

from planisphere_harness import LocalHarness

harness = LocalHarness("/private/planisphere/agents/VERSION/settings.json")
prepared = harness.before_turn(
    session_id=conversation_id, turn_id=request_id,
    cwd=project_root, prompt=user_prompt,
)
prepared = await harness.provision(prepared, resolve_context)
# Supply prepared.additional_context as untrusted data to your existing answer loop.
# After that loop produces the actual rendered response:
review = harness.after_turn(prepared, actual_response_text)

A host managing the steps itself can call harness.assess(prepared, decision) with the decision fields above. If a repair is requested, refresh with before_turn, provision the result, and continue from existing tool history once; pass repair=True to the final after_turn check. Do not replay completed actions.

JSON lifecycle for other languages

First invoke:

python3 planisphere_response.py hook --host custom --settings /private/settings.json

Send JSON on stdin with hook_event_name: "UserPromptSubmit", session_id, turn_id, cwd and prompt. Parse the JSON after PLANISPHERE LOCAL CONTEXT DATA: in hookSpecificOutput.additionalContext. An awaiting_interpretation packet is an intake, not retrieved evidence. Before composing the answer, send the assessment through:

python3 planisphere_response.py provision --host custom --settings /private/settings.json

Use the same event identity and an explicit request. The following shows an evidence assessment; replace every example value with the current intake and actual reasoning. In particular, expected_revision must be the integer from intake.task_revision, not a fixed value:

{
  "session_id": "same-conversation-id",
  "turn_id": "same-request-id",
  "cwd": "/workspace/project",
  "request": {
    "action": "assess",
    "intake_id": "exact-intake-id",
    "expected_revision": 0,
    "decision_id": "unique-decision-id",
    "outcome": "evidence",
    "question": "The current request understood in its conversation",
    "rationale": "Why the observed exchange requires additional evidence",
    "basis": [{
      "message_id": "exact-presented-message-id",
      "quote": "Exact words from that message's presented content"
    }],
    "gap": "The specific fact not established by the exchange",
    "query": "A targeted query for that missing fact"
  }
}

For conversation or clarify, omit gap and query. Consume the returned packet before answering. Changed task revisions, superseded turns and canceled intakes reject stale decisions; refresh the intake before reassessing. An exact retry may reuse the decision, but a different decision cannot replace an accepted assessment for the same intake.

After the answer, invoke hook again with hook_event_name: "Stop", the same IDs and last_assistant_message. A decision: "block" requests one continuation using reason; set stop_hook_active: true on its final check. Surface systemMessage. Use a distinct turn ID for each request and serialize each conversation. A failed process, invalid output or timeout is not a passing check.

Bounded automatic discovery

After an evidence assessment, discovery tries named originals and a narrow phrase before progressively wider term queries. It stops widening when an eligible topic candidate is found. Each topic search returns at most six distinct bodies; the correction search returns at most four and retains the successful topic scope. The packet exposes the attempted searches, deferred fallbacks and whether a result limit was reached. These are bounded discovery results, not proof of corpus completeness or semantic relevance.

The graph anchor follows the topic results' native relevance order rather than promoting required project orientation. Full originals use the turn's remaining source-character allowance (120,000 by default), with the existing cumulative 24-query and deadline limits. Refinements do not reset those limits. Unread candidates, missing required sources and originals that cannot fit remain explicit gaps; full source bodies are never replaced with undisclosed excerpts.

Check actual state

python3 planisphere_connect.py status --host claude-code \
  --destination /private/planisphere/agents

The status shows the installed version and the latest locally observed turn's policy revision, timestamps and bounded response check. Run a real host turn and match that observation before claiming activation. A manual invocation can also write these local records, so installation or status alone does not prove continuous coverage. No active workspace policy is reported as not_configured; a disabled policy stays disabled. Neither becomes an invented policy success.

A failed policy refresh prevents evidence retrieval from being reported as successful. An unavailable or changed policy at an evidence response check requests one repair and reports any remaining issue. Conversation-only and clarification outcomes do not claim a policy or source check. Host-disabled hooks or host timeouts remain outside this guarantee. Checks are heuristics, not a semantic audit or an action-permission gate.

Source excerpts stay local until the host includes them in model input; then the selected provider and its tracing/retention settings apply. Planisphere's query recorder reports metadata, not note bodies. The synchronous policy read sends no prompt, source body or response. Authentication, source access, lifecycle activation, activity-record delivery and response quality are separate checks.