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

main.ts2.2 KB
// Register the default account synchronously; stored accounts follow legacy
// adoption. Settings and each account's background work share the plugin scope.
import * as Effect from "effect/Effect";
import * as Queue from "effect/Queue";
import * as Scope from "effect/Scope";
import * as Stream from "effect/Stream";
import * as z from "zod";
import { Agents, Host, Settings, parse, runPlugin } from "convergence/effect";
import { ClaudeAgent } from "./agent.ts";
import { defaultAccount, parseInstances } from "./instances.ts";
import type { Instance } from "./instances.ts";
import { SessionStates } from "./state.ts";
import type { Job } from "./session.ts";

export const registerAccounts = Effect.fn("Claude.registerAccounts")(function* (accounts: ClaudeAgent[] = []) {
  const agents = yield* Agents;
  const scope = yield* Scope.Scope;
  const store = yield* SessionStates;
  const settings = yield* Settings;
  const account = defaultAccount();
  account.configDir = (yield* settings.get("configDir", z.string().nullish())) ?? null;
  yield* Stream.runForEach(settings.changes, (change) =>
    Effect.gen(function* () {
      if (change.key === "configDir")
        account.configDir = (yield* parse("Claude configuration folder", z.string().nullish(), change.value)) ?? null;
    }),
  ).pipe(Effect.forkScoped);
  const register = Effect.fn("Claude.register")(function* (instance: Instance) {
    const jobs = yield* Effect.acquireRelease(Queue.make<Job>(), Queue.shutdown);
    const agent = new ClaudeAgent({ instance, store, scope, jobs });
    const handle = yield* agents.register(agent.definition());
    agent.emit = handle.emit;
    accounts.push(agent);
    yield* agent.background();
  });
  yield* register(account);
  yield* store.ready;
  const stored = yield* (yield* Host).call("host/storage.get", { key: "instances" }).pipe(
    Effect.catchTag(["HostCallFailed", "PermissionNotGranted", "NeedsReview"], (error) =>
      Effect.sync(() => {
        console.warn(`claude: the stored accounts could not be read: ${error.message}`);
        return { value: null };
      }),
    ),
  );
  for (const instance of parseInstances(stored.value).slice(1)) yield* register(instance);
});
export const activate = runPlugin(SessionStates.layer, registerAccounts());

Versions

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

Reviews and comments

0 threads · 0 reviews

No comments yet.