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.test.ts2.4 KB
// The `configDir` setting (MARKETPLACE.md §15.3, STATUS gap 9): the folder
// the user chose is the default account's, and a later change applies to
// the next session without a reload.
import assert from "node:assert/strict";
import { required, test, activateAccounts as activate } from "./testing.ts";
import { fakeApi, settle } from "../sdk/testing.ts";

test("the default account registers at once, stored accounts after", async () => {
  const api = fakeApi({
    onHost: (method, params) => {
      if (method === "host/storage.get") {
        assert.equal(params.key, "instances");
        return { value: [{ id: "work", name: "Claude Work", configDir: "~/.claude_work" }] };
      }
      return {};
    },
  });
  const { agents } = activate(api);
  assert.deepEqual(
    api.registered.map((def) => def.id),
    ["claude"],
    "registered before anything is awaited",
  );
  await settle();
  assert.deepEqual(
    api.registered.map((def) => [def.id, def.name]),
    [
      ["claude", "Claude Code"],
      ["claude:work", "Claude Work"],
    ],
  );
  // The runtime tells the host of agents registered after the load.
  assert.equal(
    api.hostCalls.some((call) => call.method === "host/agents.changed"),
    false,
  );
  // Events an agent emits go out under its own id.
  agents[1].emit({ sessionId: "s", event: "run_finished", outcome: { status: "completed" } });
  assert.equal(required(api.emitted.at(-1)).agentId, "claude:work");
  // Every protocol method has a handler.
  for (const method of [
    "initialize",
    "list_options",
    "prompt",
    "rollback",
    "fork_session",
    "cancel_task",
    "usage_limits",
    "update",
    "logout",
  ] as const) {
    assert.equal(typeof api.registered[0][method], "function", method);
  }
});

test("the configuration folder from Settings is the default account's", async () => {
  const api = fakeApi({ env: { HOME: "/Users/me" }, settings: { configDir: "/Users/me/.claude-work" } });
  const { agents } = activate(api);
  await settle();
  agents[0].env = { HOME: "/Users/me" };
  assert.equal(agents[0].configDir(), "/Users/me/.claude-work");
  api.changeSettings({ configDir: null });
  await settle();
  assert.equal(agents[0].configDir(), "/Users/me/.claude", "empty is Claude Code's own");
  api.changeSettings({ configDir: "/Volumes/work/claude" });
  await settle();
  assert.equal(agents[0].configDir(), "/Volumes/work/claude");
});

Versions

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

Reviews and comments

0 threads · 0 reviews

No comments yet.