Chat & Setup (Zero-Touch ChatGPT Integration)¶
assync setup and assync chat are the zero-touch path to asking
ChatGPT a question about a registered Assync project: no second
terminal, no scripts/run-mcp-server.sh run by hand, no
export OPENAI_API_KEY. Both are built directly on top of the same
local Agents SDK client documented in
Local Assync Agent (OpenAI Agents SDK) --
same config resolution, same MCP startup, same read-only tool filter,
same agents Runner. assync-agent itself is unchanged; assync chat
reuses its underlying client code rather than duplicating it.
assync setup assync chat "..."
↓ ↓
Store API key (Keychain) Assync starts the MCP server itself
Pick a default project Assync starts the OpenAI Agent
Tool filter restricts it to 7 read-only tools
Request runs, answer prints
Assync cleans up -- no leftover process
assync setup¶
Run once per machine:
This is an interactive wizard that:
- Checks whether an OpenAI API key is already available (environment
variable or Keychain). If not, prompts for one (hidden input) and, only
after your explicit confirmation, stores it in the macOS Keychain
(service
assync.openai) -- never in a file inside this repository, never in shell history, never in an Assync record. - Lets you pick a default project id from your registered projects
(
assync project list) and saves it to your existing user config file (~/.config/assync/config.json, the same fileassync configalready manages) under theagent.default_project_idkey. - Runs the same environment diagnostics as
assync setup doctor(below) and prints the result. - Optionally -- only if you confirm -- sends one real, billed OpenAI API request ("Reply with the single word OK.") to prove the key actually works end-to-end.
--smoke-test makes step 4 available; without it, setup never makes a
network call.
Credential storage¶
The API key is stored via /usr/bin/security add-generic-password, using
its documented non-argv-exposing form (-w as the final argument, value
supplied over stdin, never as a command-line argument) -- so it never
appears in ps, shell history, or process listings. Retrieval at request
time uses security find-generic-password -w, again never exposing the
value as an argument.
Resolution order, every time a key is needed (assync chat,
assync setup doctor, assync-agent):
OPENAI_API_KEYenvironment variable, if set -- wins unconditionally, fully backward compatible with existingassync-agentusage.- macOS Keychain (
assync.openai/OPENAI_API_KEY), if the environment variable is absent. - Otherwise:
OPENAI_API_KEY_REQUIRED, and no request is made.
assync setup doctor¶
Read-only, zero-mutation environment diagnostics -- safe to run any time, never starts a real conversation:
Every check measures the real running environment; none of them infer or guess:
| Check | What it measures |
|---|---|
executable_shadowing |
Whether assync on PATH resolves (by real path, not by name) to this repository's own .venv/bin/assync, or to a different, shadowing install elsewhere on PATH. |
architecture |
Three independent, real measurements -- the interpreter's own architecture, a real compiled native dependency's architecture (file(1) on an actual .so in this venv), and whether the process is running under Rosetta 2 translation (sysctl -n sysctl.proc_translated, the documented way to detect this on Apple Silicon). Classified as NATIVE_ARCHITECTURE, ROSETTA_ACTIVE (a working setup, reported as a warning, never as broken), or ARCHITECTURE_MISMATCH (a genuinely broken, mixed-architecture venv). |
credential |
Presence and source only (SET / UNSET / INVALID, environment_variable / keychain / none) -- the key value itself never appears in the report, and doctor never makes a live API call to confirm the key works (verified_against_api is always NOT_CHECKED; that's what --smoke-test in assync setup is for). |
default_project |
Whether the configured default project id is actually registered (assync project list). |
agents_sdk_available |
Whether the openai-agents package is installed. |
runtime_validation_availability |
Whether assync.runtime.service.validate_runtime is importable -- a static availability probe only; it is never invoked, since an ad hoc chat question commonly has no ACTIVE Mission (see Runtime binding below). |
mcp_handshake |
A real stdio connection to the local Assync MCP server and a real tools/list call. |
required_tools_present |
Whether all 7 required read-only tools are present in that real tools/list result. |
process_cleanup |
Whether the MCP server subprocess used for the handshake check above is actually gone afterward (a real process-list check, not an assumption). |
overall_status is READY, READY_WITH_WARNINGS, or REPAIR_REQUIRED
(exit code 8 in the last case) -- the same three-way result
assync chat --doctor uses internally, described next.
assync chat¶
.venv/bin/assync chat "Where does project_assync currently stand?"
.venv/bin/assync chat --project-id project_other "Show completed missions"
.venv/bin/assync chat # prompts for one question interactively
.venv/bin/assync chat --doctor "..." # runs the doctor checks first
One-shot only -- there is no REPL, no /exit, no multi-turn
conversation. Each invocation is a single independent question and a
single independent Agent run, exactly like assync-agent. Assync itself:
- Resolves the API key (environment, then Keychain).
- Starts the local Assync MCP server as a subprocess.
- Builds the Agent, restricted to the same 7 read-only tools as
assync-agent(enforced by the Agents SDK's own tool filter, not just prompt text -- see Read-only guarantee). - Runs the question.
- Cleans up the MCP subprocess -- proven with a real
subprocess.Popen SIGINTtest and real init-failure/early-exit/timeout tests intests/test_agent_client_mcp.py, not merely asserting a context manager's__aexit__was called.- Prints only the final answer to stdout; a Ctrl+C during a run exits
cleanly with code
130, no raw traceback.
--doctor runs exactly the checks described above before the request --
so if assync chat isn't working, you don't have to separately run
assync setup doctor to find out why. If the result is
REPAIR_REQUIRED, the request is never attempted.
Runtime binding¶
assync chat deliberately does not create or reference a
RuntimeAssignment or RuntimeSession (see assync runtime --help for
that separate, Mission-bound subsystem). An ad hoc chat question
commonly has no ACTIVE Mission, and recording a partially-governed or
misleading runtime entry
for it would be worse than recording nothing. This is
CHAT_RUNTIME_BINDING_DEFERRED_TO_P7B -- a deliberate, explicit scope
boundary, not an oversight. Security for the read-only guarantee rests
entirely on the already-enforced MCP tool allowlist, identically to
assync-agent.
assync-agent is unchanged¶
assync-agent (the original local Agents SDK client) is not deprecated,
removed, or redirected by any of this -- it keeps working exactly as
before, including for anyone who prefers exporting OPENAI_API_KEY
manually and running the MCP server themselves. assync chat is an
additional, zero-touch entry point built on the same underlying client
code, not a replacement.
Known limitations¶
- No conversation memory across invocations -- same as
assync-agent. assync setup's interactive wizard requires a real terminal (hidden input for the API key, confirmation prompts); it is not scriptable. Everything it does can also be done by hand:export OPENAI_API_KEY(or store it in the Keychain yourself) and pick a project id withassync config set agent.default_project_id <id>.