Skip to content

agent: sign in to an agent from the chat, through ACP - #18

Merged
foxnne merged 1 commit into
mainfrom
chat-acp-auth
Oct 19, 2026
Merged

foxnne merged 1 commit into
mainfrom
chat-acp-auth

Conversation

@foxnne

@foxnne foxnne commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Part of fizzyedit/plans plans/AGENTS_ANYWHERE_PLAN.md, step 5 (sections 3–4).

What changes

  • initialize now reads the agent's authMethods and agentCapabilities.auth.logout, and
    advertises clientCapabilities.auth.terminal while some plugin registers terminal.run.
  • When session/new, session/resume, session/load, or a prompt after a sign-out comes back
    auth_required (-32000), the chat shows the agent's methods as buttons through chat.ask. It
    no longer prints "The agent refused to start". Any other refusal, or auth_required from an
    agent with no methods, still gets the old note.
  • agent method: the chat sends authenticate { methodId } and shows "Waiting for to
    sign in...". On success it opens the session again, resuming the saved one if there was one, and
    anything queued is sent. On failure it says why and shows the buttons again.
  • terminal method: the chat runs the configured agent command plus the method's args,
    with its env, through terminal.run. When that exits 0 the chat restarts the agent. Any other
    exit shows the buttons again. A terminal method is never sent to authenticate.
  • Sign out: a new palette command, "Chat: Sign Out of the Agent" (agent.sign_out), sends
    logout. It is enabled only while a running agent has auth.logout.
  • Stop while signing in stops the agent; the next message starts it again. A prompt refused for
    a sign-in is sent again once signed in. Terminal methods are shown only while terminal.run
    exists.
  • The chat never sees a token: the agent keeps its own credentials.
  • acp.Inbound.response now carries the error code.

Named seam: terminal.run

No plugin runs a program in a terminal pane yet: ghostty's plugin registers no commands. So
src/auth.zig defines the contract a terminal plugin fills:

  • Call: terminal.run { title, argv, env, cwd, done, tag }.
  • On exit, the terminal plugin calls the done command with { tag, code }.

Until a plugin offers it, the chat does not advertise auth.terminal. The spec then says the
agent should not offer terminal methods. If an agent offers them anyway, the chat shows them,
and the chat leaves it out of the buttons. If that leaves no buttons, the chat says to sign in
with the agent's own CLI.

Claude's ACP adapter (0.93.0) offers only terminal methods (claude-ai-login,
console-login: --cli auth login …). So signing a logged-out Claude in needs the ghostty
follow-up. A logged-in Claude is unaffected.

Checked against the spec

agentclientprotocol.com/protocol/authentication and the schema's ErrorCode
(auth_required = -32000), on 2026-10-19:

  • type absent means agent.
  • A terminal method's env is an object map.
  • logout takes {}, and is sent only when agentCapabilities.auth.logout is non-null.

Verify

  • zig build test: new tests in src/auth.zig cover method parsing (unknown types left out,
    terminal args/env, logout), the initialize / authenticate / logout request writers, and
    auth_required → choose → authenticate → retry, including a refusal and a terminal exit.
  • Plugin builds (Debug).
  • Live check, macOS, in a --quiet Debug fizzy from main, on its own profile, driven through
    the control socket:
    • Claude's ACP adapter (0.93.0), already logged in: "Connected." with Mode / Model / Effort
      shown. Its initialize advertises auth.logout and two terminal methods.
    • A scripted ACP agent (an agent method and a terminal one; it refuses session/new and
      prompts with -32000 until authenticate):
      • It showed one button, the terminal method left out with no terminal.run.
      • Waiting... → Signed in → Connected.
      • Stop during sign-in → "Stopped signing in", and the next message started over.
      • Sign Out → "Signed out".
      • The next prompt was refused, the person signed in again, and the same prompt was sent again
        and answered.
    • Gemini CLI is not installed here, so it was not tried.

🤖 Generated with Claude Code

The agent's `authMethods` (from `initialize`) are read; a session start (or a prompt after a
sign-out) the agent refuses with `auth_required` (-32000) shows them as buttons in the
conversation instead of "The agent refused to start". An `agent` method sends
`authenticate { methodId }`, says "Waiting for <agent> to sign in..." and opens the session
again; a `terminal` method runs the agent's own command with the method's args and env through
a `terminal.run` command, and restarts the agent when it exits 0. Terminal methods never go to
`authenticate`. "Chat: Sign Out of the Agent" sends `logout` when the agent offers it.

What happens next at each step is `auth.Flow`, std-only and tested with the method parsing and
the request writers (`src/auth.zig`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@foxnne
foxnne marked this pull request as ready for review October 19, 2026 19:51
@foxnne
foxnne merged commit b52f25b into main Oct 19, 2026
6 checks passed
foxnne added a commit to fizzyedit/ghostty that referenced this pull request Oct 19, 2026
Registers the internal command `terminal.run` that fizzyedit/chat#18 defined, so the chat's
terminal sign-in (Claude Code's ACP adapter offers only `claude /login`) works. The program runs in
a bottom-panel pane of its own with the request's argv, env and cwd; on exit the pane keeps its
output with the exit code and a Close button, and the caller's `done` command gets `.{ tag, code }`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
foxnne added a commit to fizzyedit/ghostty that referenced this pull request Oct 19, 2026
)

Registers the internal command `terminal.run` that fizzyedit/chat#18 defined, so the chat's
terminal sign-in (Claude Code's ACP adapter offers only `claude /login`) works. The program runs in
a bottom-panel pane of its own with the request's argv, env and cwd; on exit the pane keeps its
output with the exit code and a Close button, and the caller's `done` command gets `.{ tag, code }`.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant