The /admin Skill -- Managing Access Control from Claude Code

The Orchestrator’s access control system – roles, permissions, users, audit trails – can now be managed entirely through Claude Code using the /admin slash command.

Why a Skill?

Claude Code connects to the WorkingAgents MCP server, which exposes access control as remote tools. The problem: without explicit guidance, the AI might try to edit Elixir source files or poke at SQLite databases instead of using the live admin API.

The /admin skill solves this by loading a prompt that says: “use the MCP tools, never touch code directly.” It maps natural language requests to the right tool calls automatically.

Usage

Type /admin followed by what you want:

/admin list all roles
/admin what permissions does user 3 have?
/admin create a role called "analyst" with access to knowledge and blog
/admin give bob temporary access to task manager for 1 hour
/admin show me the audit log for the last 50 actions
/admin revoke the editor role from user 5
/admin system health check

What It Covers

How It Works

The skill is a Markdown file at .claude/skills/admin/SKILL.md. Claude Code loads it when you invoke /admin, and it instructs the AI to:

  1. Gather context first (look up user IDs, list available modules)
  2. Use only the mcp__remote__access_control_* tools
  3. Never expose raw permission key integers – show module and role names
  4. Confirm destructive actions before executing
  5. Verify changes after making them

The Skill Script

---
name: admin
description: Use when the user asks to manage users, roles, permissions,
  access control, or audit logs. Covers granting/revoking permissions,
  defining/assigning/deleting roles, viewing user permissions, checking
  system health, and querying audit trails.
user-invocable: true
---

# Admin -- Access Control Management

Manage users, roles, and permissions on the live WorkingAgents server
using the remote MCP tools. **Never edit code or databases directly** --
always use the MCP access control tools.

## Available MCP Tools

| Tool | Purpose |
|------|---------|
| `access_control_health` | System health stats |
| `access_control_list_modules` | List all protected modules and their permission keys |
| `access_control_list_roles` | List all defined roles |
| `access_control_define_role` | Create or update a role (name, keys[], description) |
| `access_control_delete_role` | Delete a role by name |
| `access_control_assign_role` | Assign a role to a user (user_id, role_name) |
| `access_control_revoke_role` | Revoke a role from a user |
| `access_control_user_permissions` | View a user's permissions and roles (user_id) |
| `access_control_grant` | Grant permission keys to a user (user_id, keys[], optional ttl) |
| `access_control_revoke` | Revoke permission keys from a user |
| `access_control_audit_log` | Query audit trail (optional: user_id, action, limit) |

## Workflow

1. **Understand the request** -- parse what the user wants
2. **Gather context** -- look up user IDs, list modules, check current state
3. **Make changes** -- use permission keys from `list_modules`, never guess
4. **Verify and report** -- confirm the change took effect

## Rules

- Permission keys are integers from `list_modules` -- never invent values
- Keys never leave the server -- show module names, not raw integers
- Confirm destructive actions before executing
- Use TTL (seconds) for temporary access grants
- After changes, mention that the action is recorded in the audit log

Key Design Decisions

Why MCP tools instead of IEx? The MCP tools go through the same permission and audit layer that every other client uses. Running raw Elixir in IEx bypasses audit logging and permission checks.

Why hide permission keys? Keys are internal identifiers. Exposing them in conversation creates a leaking abstraction – users should think in terms of “TaskManager access” not “key 847291”.

Why verify after changes? The access control system has a lazy expiry model for TTL grants. Verifying confirms the change is visible immediately rather than waiting for cache refresh.