Skip to content

Local Assync Agent (OpenAI Agents SDK)

assync-agent is a small local CLI that lets you ask natural-language questions about a registered Assync project and get an answer grounded exclusively in Assync's own read-only MCP tools. It is built on OpenAI's Agents SDK (openai-agents) and talks to the same local assync mcp stdio server that ChatGPT's Developer Mode integration uses (see ChatGPT Developer Mode) -- nothing about the server changes for this client.

Want zero manual setup instead?

assync-agent requires a second terminal running scripts/run-mcp-server.sh by hand and an exported OPENAI_API_KEY. assync chat (built on top of this same client -- see Chat & Setup) starts the MCP server itself, reads the key from the macOS Keychain, and exits when done. Everything on this page about the read-only guarantee, tool filter, and tracing applies identically to both.

You
OpenAI Agents SDK (Agent + Runner, running locally)
OpenAI model, over the OpenAI API
Assync MCP server (scripts/run-mcp-server.sh, stdio, unchanged)
Project · Mission · Handoff · Decision · Audit

How this differs from the ChatGPT Developer Mode integration

The ChatGPT integration runs inside ChatGPT's own web UI, using your ChatGPT account and (for Developer Mode) a Secure MCP Tunnel. This client is a separate, local, standalone application: your own process, calling the OpenAI API directly with your own API key. Its usage is billed separately, as OpenAI API usage -- a ChatGPT Plus/Pro subscription does not include API credits. Both approaches connect to the exact same unmodified local MCP server; you can use either, or both, independently.

Setup

Install the extra (adds openai-agents on top of the existing mcp extra used by the server side):

.venv/bin/pip install -e ".[agent]"

Set your API key in the environment -- never in a file inside this repository, never as a command-line argument, never committed:

export OPENAI_API_KEY="sk-..."

Running it

.venv/bin/assync-agent "Where does project_assync currently stand?"
.venv/bin/assync-agent --project-id project_assync "Show completed missions"

By default stdout prints only the agent's final answer; diagnostics (and any error) go to stderr, with a non-zero exit code on any startup, MCP, or model/tool failure. A missing OPENAI_API_KEY produces OPENAI_API_KEY_REQUIRED and exits before any request is made.

Example questions:

  • "Where does project_assync currently stand?"
  • "List the missions for project_assync and say which are completed."
  • "What execution handoffs exist for project_assync, and what state are they in?"
  • "What decisions are still pending for project_assync?"

Model

The default model is gpt-5.4-mini (the Agents SDK's own recommended low-latency default for tool-using agents at the time this was written). Override it with:

export ASSYNC_AGENT_MODEL="gpt-5.6-sol"   # or any other current model

Read-only guarantee

This client can only ever reach 7 tools, enforced through the Agents SDK's own MCP tool filter (create_static_tool_filter, see src/assync/agent_client/mcp.py) -- not merely through the agent's prompt instructions:

  • assync_status_show
  • assync_mission_list
  • assync_mission_show
  • assync_execution_handoff_list
  • assync_execution_handoff_show
  • assync_decision_list
  • assync_decision_show

Every other tool the MCP server exposes (mission/decision/handoff mutations, authorization minting, project registration, and so on) is never listed to the model in the first place. If a model attempts to call a filtered-out tool anyway (e.g. via a prompt-injection attempt), the Agents SDK raises ModelBehaviorError: Tool <name> not found before the call ever reaches the real MCP server -- verified directly against the real server in tests/test_agent_client_workflow.py::test_blocked_mutating_tool_call_fails_closed_with_no_mutation and exercised again as eval cases 7 and 8. No Authorization is created, no Decision is resolved, no Handoff is accepted, no Mission is transitioned by this client, ever.

Tracing

The Agents SDK enables tracing by default and exports run traces (model calls, tool calls, MCP activity) to OpenAI's backend (platform.openai.com/traces) using the same OPENAI_API_KEY. Disable it locally if you don't want that:

export OPENAI_AGENTS_DISABLE_TRACING=1

Assync's own Audit log and the Agents SDK's tracing are separate systems that must not be conflated: Audit records Assync governance events (mission/decision/handoff state), tracing records model/tool execution inside a single agent run. This client does not write anything to tracing beyond what the SDK does by default, and does not implement a second tracing system.

Known limitations

  • No conversation memory across invocations -- each assync-agent call is one independent question and one independent Agent run.
  • No streaming output -- the CLI waits for the full run and prints the final answer.
  • Model answers about mission/decision/handoff content are only as good as the model's summarization of the real tool output; the underlying data itself is always the real, current Assync state (never invented), but phrasing is not deterministic.

Running the tests

Offline (no OpenAI API calls, no cost) -- config/CLI, MCP tool-filter and lifecycle (against the real local server), and fake-model workflow tests:

/path/to/isolated/python3.11/bin/python -m pytest \
  tests/test_agent_client_config.py \
  tests/test_agent_client_cli.py \
  tests/test_agent_client_mcp.py \
  tests/test_agent_client_workflow.py

(Use this repository's isolated architecture-consistent Python 3.11 environment, not the machine's global interpreter -- see Installation.)

Running the real API smoke test

Requires OPENAI_API_KEY. Calls the real OpenAI API once:

export OPENAI_API_KEY="sk-..."
.venv/bin/assync-agent "Use Assync to report where project_assync currently stands."

Verify the answer's project id, branch, and HEAD against a direct read-only check (assync status --json) to confirm the tool result was genuinely used, not invented.

Running the evals

evals/assync_agent/ contains 8 cases (project status; missions; handoffs; decisions; unknown project; unsupported question; a prompt-injection attempt asking for a mutating tool call; a request to accept a handoff). Requires OPENAI_API_KEY and calls the real OpenAI API once per case (8 calls total) -- real, small usage cost, no mocked model:

export OPENAI_API_KEY="sk-..."
/path/to/isolated/python3.11/bin/python -m evals.assync_agent.run_evals

Grading is criteria-based (expected tool category used, forbidden tools never actually invoked, NOT_VERIFIED-style honesty where expected, and a full before/after snapshot of every mutable Assync record proving no mutation occurred across the whole run) -- never exact prose matching, since real model phrasing varies run to run. Response clarity is printed for human review, not auto-graded.