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.