# Admin Groups

> Explain and manage group membership, manager inheritance, special groups, and canonical group.yaml storage as an admin.

- Skill: `agent0ai/admin-groups` (Agent Skill)
- Install (CLI): `npx skillmds@latest add agent0ai/admin-groups`
- Raw SKILL.md: https://api.skillmd.com/api/skills/agent0ai/admin-groups/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: agent0ai (https://skillmd.com/u/agent0ai)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/agent0ai/admin-groups

---


Use this skill for group creation, membership changes, manager changes, or explaining how `_all` and `_admin` work.

## Canonical Group Tree

- Runtime-managed groups live under `L1/<group>/`.
- `L1/<group>/group.yaml` is the canonical membership and manager file.
- `L1/<group>/mod/` is that group's customware module root.

Do not write group membership into arbitrary files. `group.yaml` is the contract.

## Special Groups

- `_all` is the implicit everyone group.
- Do not create or rely on `L1/_all/group.yaml` for membership. `_all` membership is universal, not file-driven.
- `_admin` is the admin group.
- Adding a user or included group to `_admin` makes those users admins.

## Canonical group.yaml Fields

- `included_users`
- `included_groups`
- `managing_users`
- `managing_groups`

Meaning:

- `included_users`: direct members of the group
- `included_groups`: groups whose members also become members of this group
- `managing_users`: users who may write this group's `L1/<group>/` tree
- `managing_groups`: groups whose members may write this group's `L1/<group>/` tree

Manager inheritance is separate from membership inheritance. Do not treat `included_*` as manager fields or vice versa.

## Create A Group

Runtime-created groups belong in `L1`, not `L0`.

```js
const groupId = "team-red";

return await space.api.fileWrite({
  files: [
    { path: `L1/${groupId}/` },
    { path: `L1/${groupId}/mod/` },
    {
      path: `L1/${groupId}/group.yaml`,
      content: space.utils.yaml.stringify({
        included_groups: [],
        included_users: [],
        managing_groups: [],
        managing_users: []
      })
    }
  ]
});
```

## Update Membership Or Managers

Read, parse, normalize, then write `group.yaml`.

```js
const path = "L1/team-red/group.yaml";
const current = await space.api.fileRead(path);
const config = space.utils.yaml.parse(current.content || "");

config.included_users = [...new Set([...(config.included_users || []), "alice"])].sort();
config.managing_users = [...new Set([...(config.managing_users || []), "alice"])].sort();

return await space.api.fileWrite(path, space.utils.yaml.stringify(config));
```

Use the same pattern for `included_groups` and `managing_groups`.

## Grant Or Remove Admin Access

The canonical way to grant admin access is to edit `L1/_admin/group.yaml`:

- add usernames to `included_users`
- or add groups to `included_groups`

Example:

```js
const path = "L1/_admin/group.yaml";
const current = await space.api.fileRead(path);
const config = space.utils.yaml.parse(current.content || "");
config.included_users = [...new Set([...(config.included_users || []), "alice"])].sort();
return await space.api.fileWrite(path, space.utils.yaml.stringify(config));
```

## Mental Model

- membership answers "which users belong to this group?"
- manager lists answer "which users may write this group's L1 tree?"
- `_admin` membership is stronger than ordinary group management because admins may write any `L1/*` and `L2/*`
- `_all` is readable by everyone, but it is not the place to store membership rules

## CLI Reference

Backend equivalents exist for operators outside the browser:

- `node space group create <group-id>`
- `node space group add <group-id> <user|group> <id> [--manager]`
- `node space group remove <group-id> <user|group> <id> [--manager]`

From the overlay agent, prefer logical app-file edits through `space.api`.

