Skip to content

Add Pinky ACP daemon connector - #957

Merged
olegbrok merged 3 commits into
mainfrom
agent/buzz-acp-connector
Jul 31, 2026
Merged

Add Pinky ACP daemon connector#957
olegbrok merged 3 commits into
mainfrom
agent/buzz-acp-connector

Conversation

@bradbrok

@bradbrok bradbrok commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Outcome

Adds pinky acp, a protocol-clean stdio connector that lets a configured PinkyBot agent run as a Buzz Custom harness while delegating turns to dedicated daemon manager sessions. It also closes the pre-existing daemon gap that accepted manager-session permission policy without propagating it to the SDK runner.

What changed

  • Add PinkyAcpAgent on the official Zed ACP Python SDK and a signed async DaemonClient.
  • Negotiate ACP protocol version 1 with load-session and HTTP/SSE MCP capabilities disabled and no auth methods.
  • Map session/new to generic POST /sessions, rooted at data/agents/{agent} rather than the ACP client's cwd.
  • Copy model, allowed/disallowed tools, turn limits, timeout, restart settings, and the ACP-effective permission mode into the daemon session.
  • Propagate manager-session permission_mode into SDKRunnerConfig; unset non-ACP callers retain the existing bypassPermissions behavior.
  • Add disallowed_tools to CreateSessionRequest and thread it through POST /sessions to SDKRunnerConfig.
  • Flatten prompt content blocks into daemon text, return one agent_message_chunk, and finish with end_turn.
  • Emit thought-chunk keepalives every 60 seconds during long turns.
  • Implement cancel-as-detach with stopReason: cancelled; the daemon turn is intentionally not interrupted until a daemon cancel endpoint exists.
  • Retry daemon 409/busy responses through a bounded wait. Exhaustion becomes an ACP refusal/message, never a JSON-RPC handler error.
  • Warn to stderr and ignore client MCP servers; daemon-managed .mcp.json stays authoritative.
  • Read PINKY_SESSION_SECRET from the environment or checkout .env, and HMAC-sign every daemon call.
  • Add the acp optional extra and install it in CI so connector tests execute.

ACP policy boundary

Stdout is exclusively ACP JSON-RPC; all diagnostics and policy disclosures go to stderr.

  • By owner ruling, Buzz stays secured: bypassPermissions is prohibited on the ACP surface from every source. Agent-config bypass is downgraded to dontAsk; PINKY_ACP_PERMISSION_MODE=bypassPermissions is refused with an owner-policy stderr disclosure and also resolves to dontAsk.
  • A non-empty PINKY_ACP_PERMISSION_MODE may select any non-bypass mode verbatim. Without such an override, an empty agent mode is sanitized to dontAsk, which denies calls not pre-approved by allow rules.
  • Under dontAsk, a non-empty agent allowed_tools list is preserved. If it is empty, ACP supplies: Bash, Read, Glob, Grep, Edit, Write, and the pinky memory/messaging/self MCP namespaces.
  • A strict-mode allowlist without Bash emits a stderr warning that Buzz's CLI reply path will be denied.
  • disallowed_tools is carried separately and removes tools from availability.

The rail is tool-granular: allowing Bash auto-approves all shell commands, not only buzz messages send; command-level policy is unavailable at this layer.

Blast-radius audit

Production manager-backed creation has four entry shapes:

  1. Generic POST /sessions passes the request mode. Omitted/empty remains bypass for compatibility; explicit modes are now enforced.
  2. Clone-worker creation passes agent.permission_mode.
  3. POST /agents/{name}/sessions passes agent.permission_mode.
  4. Persisted restore passes the stored mode.

The current configured-agent snapshot has no default or plan modes and zero active manager sessions, so no live headless path flips into an interactive prompting mode.

  • auto: kotik, kuzya, mora, ryzhik, solik, vaska. Their future SDK manager sessions now receive auto, whose SDK behavior is classifier approval/denial rather than prompting.
  • bypassPermissions: barsik, dymok, murzik, persik, pushok. Non-ACP manager behavior is unchanged; ACP always sanitizes these to dontAsk.

No other production manager.create or direct manager Session(...) call sites were found.

Known v0 limitations

Verification

Exact replacement head: 053e2ca2f2f119416ba6f8c0206787042fc19f4a.

  • Python 3.11: final ACP policy plus CLI plus API runner boundary — 23 passed.
  • Python 3.11: SDK runner plus session store — 42 passed.
  • Python 3.11: TestSession + TestAPI — 139 passed; the sole failure is the unchanged manual-dream test selecting real local tmux/Claude while shared MCP port 8890 is occupied by the running daemon. This is the same pre-existing local-environment failure previously classified on this PR.
  • Real ACP subprocess handshake over stdio; daemon boundaries use httpx.MockTransport.
  • Regressions assert requested mode reaches SDKRunnerConfig, disallowed_tools reaches it end-to-end from POST /sessions, bypass/empty ACP policy resolves to strict mode, defaults are injected only for an empty strict-mode allowlist, non-empty agent policy is preserved, missing Bash warns, the env bypass override is refused by owner policy, and non-bypass env overrides remain verbatim.
  • Ruff, lock check, compileall, and git diff --check clean.
  • Base-only wheel verification remains valid: pinky --help works; invoking pinky acp without the optional extra exits 2 with actionable stderr and empty stdout.

Provenance

Implemented by Kuzya from Barsik's Buzz/ACP research brief and task #496 specification. Daemon enforcement and ACP policy corrections incorporate Murzik's review findings and Barsik's final policy direction.

🤖 Opened by Kuzya

Comment thread src/pinky_cli/acp.py Fixed
@olegbrok
olegbrok marked this pull request as ready for review July 31, 2026 21:28
@olegbrok
olegbrok merged commit ce4b3c7 into main Jul 31, 2026
11 checks passed
@olegbrok
olegbrok deleted the agent/buzz-acp-connector branch July 31, 2026 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants