Official

claude

Claude Code agent provider: runs the Claude Code CLI headless for each account.

The app opens the listing; nothing installs until an agent in your Plugins workspace has read the files and you enable the plugin. In a terminal: cvg install convergence/claude@0.2.0

Permissions in 0.2.0

  • Provide agents agents.provideMediumAdds agents to the app.Provide the Claude Code agent and pass its tool calls to plugin tools
  • Run named programs processMediumStarts the listed programs.Run the Claude Code CLI (sessions, sign-in, `claude update`), and ask the npm installation that owns it about a newer versionPrograms: claudenpm
  • Read files fs.readMediumReads files in the listed places.Read Claude Code's sessions, settings and skills (in ~/.claude, other accounts' ~/.claude-* folders, the shared skills and the folder you choose in Settings), the project's .claude folder, the administrator's skill policy, and once, what the previous provider keptPlaces: ~/.claude/**~/.claude*/**~/.agents/skills/**the open workspaceits own data folder/Library/Application Support/ClaudeCode/managed-settings.json/etc/claude-code/managed-settings.json${settings.configDir}
  • Environment variables envMediumReads the listed environment variables.Find Claude Code's configuration directory, and the launch settings you set in CLAUDE_* variables (extra arguments, MCP servers, setting sources, appended system prompt, extra folders)Variables: HOMECLAUDE_CONFIG_DIRCLAUDE_EXTRA_ARGSCLAUDE_MCP_CONFIGCLAUDE_STRICT_MCP_CONFIGCLAUDE_SETTING_SOURCESCLAUDE_APPEND_SYSTEM_PROMPTCLAUDE_ADD_DIRS

Files

transport.ts1.9 KB
// Claude's line transport uses the SDK's ordered writer and pipe reader.
// Acquisition and graceful shutdown belong to the provider's Effect scope.
import * as Effect from "effect/Effect";
import { Process } from "convergence/effect";
import { LineProcess } from "../sdk/process.ts";
import type { LineProcessOptions } from "../sdk/process.ts";
import { TransportFailed } from "../sdk/effect.ts";
import { errorMessage } from "../sdk/errors.ts";

const attempt = Effect.fnUntraced(function* <A>(run: () => Promise<A>) {
  return yield* Effect.tryPromise({
    try: run,
    catch: (cause) => new TransportFailed({ message: errorMessage(cause), cause }),
  });
});
export const stop = Effect.fn("Claude.transport.stop")(function* (peer: LineProcess, grace = 2000) {
  peer.closedReason ??= "shut down";
  if (peer.exitStatus !== null) return yield* attempt(() => peer.ended);
  // Closed input or an already exited peer needs no further cleanup.
  yield* attempt(() => peer.child.stdin.close()).pipe(Effect.catchTag("TransportFailed", () => Effect.void));
  yield* attempt(() => peer.kill("SIGTERM")).pipe(Effect.catchTag("TransportFailed", () => Effect.void));
  const exited = yield* Effect.raceFirst(
    attempt(() => peer.exited).pipe(Effect.as(true)),
    Effect.sleep(grace).pipe(Effect.as(false)),
  );
  if (!exited) yield* attempt(() => peer.kill("SIGKILL")).pipe(Effect.catchTag("TransportFailed", () => Effect.void));
  // Exit and stdout completion are separate: drain before releasing the line queue.
  else yield* attempt(() => peer.ended);
});
export const spawn = Effect.fn("Claude.transport.spawn")(function* (args: string[], options: LineProcessOptions) {
  const child = yield* (yield* Process).spawn("claude", args, { cwd: options.cwd, env: options.env });
  return yield* Effect.acquireRelease(
    Effect.sync(() => new LineProcess(child, options)),
    (peer) => stop(peer).pipe(Effect.orDie),
  );
});

Versions

VersionPublishedPlugin APISizePermissionsStatus
0.2.0latestOct 5, 2026>=2 <3128.7 KB4 permissionsListed

Reviews and comments

0 threads · 0 reviews

No comments yet.