---
id: PRD-0005
title: "M4 — Control & Admin CLI, Gated Admin Tools, /join Skill"
status: done
owner: "Aaron Roney"
created: 2026-07-01
updated: 2026-07-02

depends_on:
- PRD-0004

principles:
- "One CLI, two roles + control verbs (DESIGN §2/§13)."
- "The bridge is installed once as an MCP server; /join does not launch it — it calls join_channel on the running bridge (DESIGN §13)."
- "Admin tools are capability-gated: offered/accepted only for admin users (DESIGN §7)."

references:
- name: "Conclave design (admin §7, components/CLI §13, join skill §13)"
  url: "docs/DESIGN.md"
- name: "kord/ratrod clap-derive CLI + README --help-verbatim usage docs"
  url: "https://github.com/twitchax/ratrod"

acceptance_tests:
- id: uat-001
  name: "Control verbs work end-to-end: register, machine add/list/remove, key, join, perm set/show"
  command: cargo nextest run -E 'test(/cli_control/)'
  uat_status: verified
- id: uat-002
  name: "Admin verbs work for an admin user and are refused for a non-admin: channel create/delete, acl add/remove, invite create/revoke, kick, ban, user list/remove"
  command: cargo nextest run -E 'test(/cli_admin/)'
  uat_status: verified
- id: uat-003
  name: "Gated MCP admin tools are exposed only to admin users (non-admin session cannot call them)"
  command: cargo nextest run -E 'test(/bridge_admin_tools/)'
  uat_status: verified
- id: uat-004
  name: "/join skill drives a connect+subscribe on the running bridge (with --perm) end-to-end"
  command: cargo nextest run -E 'test(/e2e_join_skill/)'
  uat_status: verified

tasks:
- id: T-001
  title: "Control CLI verbs (clap derive)"
  priority: 1
  status: done
  notes: "register, machine add/list/remove, key (gen/show pubkey), join, perm set/show. Dispatch to the server control RPCs / local config. README documents each --help verbatim."
- id: T-002
  title: "Admin CLI verbs"
  priority: 1
  status: done
  notes: "channel create/delete/rename/set-visibility, acl add/remove, invite create/revoke, kick <session|user>, ban <user>; server-admin user list/remove, machine remove. Authorized by role server-side."
- id: T-003
  title: "Gated MCP admin tools"
  priority: 2
  status: done
  notes: "Expose admin operations as MCP tools that the bridge offers/accepts only when the connected user is an admin (server confirms role). Non-admin agents cannot see or call them."
- id: T-004
  title: "/join Claude Code skill"
  priority: 1
  status: done
  notes: "Skill that assumes the conclave bridge is pre-installed as an MCP server (running-but-offline), and calls its join_channel tool: /join <server> <channel> [--as handle] [--perm level]. Include the one-time bridge install instructions (MCP config) in DEVELOPMENT.md / skill docs."
- id: T-005
  title: "CLI + skill e2e coverage"
  priority: 2
  status: done
  notes: "e2e tests exercising each verb group against a live serve, plus the /join flow driving a real bridge subscribe. Assert admin gating (non-admin refusal)."
---

# Summary

The human/agent control surface: the full `conclave` CLI (control + admin verbs), the gated MCP
admin tools, and the `/join` Claude Code skill that connects a running bridge to a server/channel.

# Problem

M2/M3 expose the mechanics; this milestone makes them usable — a person (or agent) can register,
enroll machines, join, set permissions, and administer channels, and a session can `/join` without
hand-editing config.

# Goals

1. Complete control + admin CLI verbs, role-authorized server-side.
2. Admin operations also available as capability-gated MCP tools.
3. A `/join` skill that connect+subscribes the pre-installed bridge (with `--perm`).

# Technical Approach

Extend the `clap`-derive CLI with the control and admin verbs, each dispatching to the M2 control
RPCs or local config. Admin verbs are authorized by role on the server. The same admin operations
are surfaced as MCP tools the bridge only advertises to admin users. The `/join` skill is a thin
Claude Code skill: it does not launch the bridge (that's a one-time MCP-server install) — it calls
`join_channel` on the already-running bridge, passing server/channel/handle/perm. README shows each
subcommand's `--help` verbatim (ratrod/kord convention).

# Assumptions

- M3 bridge exposes tool-call handling and the server exposes admin RPCs (M2).
- The conclave bridge MCP server can be pre-installed in the user's CC MCP config (one-time).

# Constraints

- `/join` cannot start an MCP server mid-session (DESIGN §13) — it only drives a running bridge.

# References to Code

- `docs/DESIGN.md` §7 (admin), §13 (CLI + /join skill).
- kord/ratrod: `clap` derive CLI, README `--help`-verbatim usage sections.

# Non-Goals (MVP)

- Invite/visibility polish, live `perm set` hot-reload, multi-home UX (M5).

# History
(Entries appended during implementation go below this line.)

## 2026-07-02 — M4 executed (T-001…T-005)

The control/admin CLI, gated admin MCP tools, and the packaged skill landed with TDD; `cargo make
ci` is green (111 tests). All four UATs pass: `test(/cli_control/)` (1), `test(/cli_admin/)` (1),
`test(/bridge_admin_tools/)` (2), `test(/e2e_join_skill/)` (1).

**Skill design — reframed with Aaron (confirmed decision).** Rather than a thin, separate `/join`
skill that "knows how to drive the CLI," the **CLI owns one comprehensive `conclave` skill** and
joining is one section of it. `conclave skill` prints a complete `SKILL.md`; `conclave skill install
[--dir]` writes it under `~/.claude/skills/conclave/` so `/conclave` becomes available. Content is a
**hybrid**: a curated guide (mental model, the two surfaces — in-session MCP tools vs. the setup/admin
CLI, the one-time dev-channel install) authored in `src/skill/SKILL.md`, followed by an
**auto-generated command reference walked from the clap tree** so the flag list never drifts. The
curated body lives in the lib; the binary supplies the rendered `--help` (clap lives in the binary).

Structure:

- **CLI verbs** (`bin.rs`, clap-derive) dispatch to a new one-shot **`control`** client (connect →
  auth/register → one request/response → disconnect) or to local config: `key` (local), `register`
  (+ save registration), `machine add/list/remove`, `join` (verify + set local perm), `perm set/show`
  (local), `channel/acl/invite/kick/ban/user …` (server, role-authorized), `skill show/install`.
  `--config-dir` is a global flag; one-shot ops use a per-pid `cli-<pid>` session handle to avoid
  colliding with a live bridge.
- **Gated admin MCP tools** (`bridge`): the server sends a post-auth `ServerInfo { admin }` frame;
  the bridge offers `create_channel` / `delete_channel` / `set_visibility` / `acl_add` / `acl_remove`
  / `invite_create` / `invite_revoke` / `kick` / `ban` **only** to admins. The server re-authorizes by
  role, so gating is defense-in-depth.

Additive protocol frames (appended, forward-compat; version stays 1): `ServerInfo { admin }`,
`ListMachines` / `MachineList { [MachineInfo] }`, `ListUsers` / `UserList { [String] }`. Existing test
harnesses updated to consume the trailing `ServerInfo` after `Established`.

Deps: `serde_json` already present; new `gethostname` (the `register --machine` hostname default).
`serve --admin <user>` (M2) is the server-admin allowlist the gating checks against.
