@awebai/claude-skills 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "aweb-skills",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "aweb agent coordination skills — teach your Claude Code agent how to use the aw CLI for mail, chat, tasks, and team coordination."
5
5
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@awebai/claude-skills",
3
- "version": "0.2.1",
4
- "description": "Content-only Claude Code plugin shipping the canonical aweb agent-coordination skills: aweb-coordination, aweb-messaging, aweb-team-membership, aweb-bootstrap.",
3
+ "version": "0.2.3",
4
+ "description": "Content-only Claude Code plugin shipping the canonical aweb agent-coordination skills: aweb-coordination, aweb-messaging, aweb-team-membership, aweb-bootstrap, aweb-identity.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://aweb.ai",
7
7
  "repository": {
@@ -23,7 +23,7 @@
23
23
  "package.json"
24
24
  ],
25
25
  "scripts": {
26
- "sync-skills": "rm -rf skills && mkdir -p skills && cp -R ../../skills/aweb-coordination ../../skills/aweb-messaging ../../skills/aweb-team-membership ../../skills/aweb-bootstrap skills/",
26
+ "sync-skills": "rm -rf skills && mkdir -p skills && cp -R ../../skills/aweb-coordination ../../skills/aweb-messaging ../../skills/aweb-team-membership ../../skills/aweb-bootstrap ../../skills/aweb-identity skills/",
27
27
  "sync-plugin-version": "node -e \"const p=JSON.parse(require('fs').readFileSync('.claude-plugin/plugin.json','utf8')); p.version=require('./package.json').version; require('fs').writeFileSync('.claude-plugin/plugin.json',JSON.stringify(p,null,2)+'\\n')\"",
28
28
  "prepack": "npm run sync-skills && npm run sync-plugin-version",
29
29
  "prepublishOnly": "npm run sync-skills && npm run sync-plugin-version"
@@ -1,123 +1,178 @@
1
1
  ---
2
2
  name: aweb-coordination
3
- description: This skill should be used when starting work in an aweb-coordinated team, checking team status, finding or claiming work, using locks, coordinating handoffs, requesting reviews, managing role/instruction context, or deciding whether to record team coordination in shared aweb state instead of private notes.
3
+ description: This skill should be used when working in an aweb-coordinated team checking what teammates are doing, discovering and sharing tasks, claiming work, taking manual locks on contested resources, reading or setting shared team roles and instructions, creating sibling worktrees with `aw workspace add-worktree`, and deciding whether to record coordination in shared aweb state versus private notes.
4
4
  allowed-tools: "Bash(aw *)"
5
5
  ---
6
6
 
7
7
  # aweb Coordination
8
8
 
9
- Use this skill to coordinate work with a team of agents through aweb. Focus on decision policy: when to check state, when to claim work, when to lock resources, when to hand off, and when to escalate.
9
+ Use this skill when sharing work with a team of agents through aweb. Focus on the **decision policy**: when to inspect shared state, when to claim tasks, when to take a lock, how to read the team's operating rules, and how to create a fresh worktree. Command help is one `aw <verb> --help` away — this skill is here for the judgment calls help cannot supply.
10
10
 
11
- For mail/chat mechanics, load `aweb-messaging`. For joining teams, multiple memberships, team certificates, hosted/BYOT, custody, addressability, inbound mode, or contacts, load `aweb-team-membership`.
11
+ For mail/chat response policy, load `aweb-messaging`. For identity, team certificates, multi-team membership, hosted/BYOT authority, custody, addressability, or contacts, load `aweb-team-membership`. For creating a new aweb team from a template, load `aweb-bootstrap`.
12
+
13
+ ## What aweb gives the team
14
+
15
+ A short map of the primitives this skill assumes are available. Each has its own `aw` verb; their decision policy lives here, their command details live in `aw <verb> --help`.
16
+
17
+ - **Tasks** (`aw task`) — the durable record of work items: create, list, show, update, comment, close.
18
+ - **Work discovery** (`aw work`) — the dashboard-style view over those tasks combined with current claim state: `ready` (unclaimed), `active` (in-progress across the team), `blocked`.
19
+ - **Mail** (`aw mail`) — async, signed, durable; the default for handoffs and review requests. Details in `aweb-messaging`.
20
+ - **Chat** (`aw chat`) — sync, signed, waits on a response. Details in `aweb-messaging`.
21
+ - **Locks** (`aw lock`) — explicit, manual coordination primitives for contested resources. Not automatic.
22
+ - **Presence** — `aw workspace status` shows who is online; `aw heartbeat` sends an explicit presence beat.
23
+ - **Roles** (`aw roles`, `aw role-name`) — a versioned bundle of role definitions plus the current workspace's role assignment.
24
+ - **Instructions** (`aw instructions`) — a versioned shared team-instructions document every agent reads on wake-up.
25
+ - **Worktrees** (`aw workspace add-worktree`) — create a sibling git worktree wired up as its own coordination workspace.
12
26
 
13
27
  ## Start-of-session loop
14
28
 
15
- Run the coordination checks before starting new work:
29
+ Run these before claiming new work. Order is deliberate.
16
30
 
17
31
  ```bash
18
- aw workspace status
19
- aw mail inbox
20
- aw chat pending
21
- aw work ready
32
+ aw workspace status # who is online, active team, identity, claims, locks
33
+ aw mail inbox # async handoffs, reviews, blockers — process first
34
+ aw chat pending # someone may be blocked waiting on you
35
+ aw work ready # only after the above; pick the smallest actionable item
22
36
  ```
23
37
 
24
- Use this order deliberately:
38
+ If `aw workspace status` reports the directory is not bound to a team (no `.aw/workspace.yaml`, no certificate, etc.), stop and load `aweb-team-membership` before doing coordination work.
39
+
40
+ ## Seeing what teammates are doing
41
+
42
+ Before you claim work or send a message, get the team's current state. These are read-only and cheap:
43
+
44
+ - `aw work active` — every task currently claimed across the team, who has it, and the status. The first place to look when wondering "is someone already on this?"
45
+ - `aw work ready` — unclaimed tasks the team would benefit from picking up.
46
+ - `aw work blocked` — tasks paused on a dependency or external answer.
47
+ - `aw task list` — full task index with filters (status, assignee, label).
48
+ - `aw task show <task-id>` — full task including comments, dependencies, and history.
49
+ - `aw workspace status` — presence for the active team (who is online right now).
50
+ - `aw mail inbox` and `aw chat history <alias>` — recent messages, including what teammates have been talking about.
51
+
52
+ Some teammates may be members of more than one team. The commands above only show the active team's state. To check another team in passing, use `--team <team-id>`; to switch persistently, use `aw id team switch` (covered in `aweb-team-membership`).
53
+
54
+ ## Contacting teammates
25
55
 
26
- 1. **Workspace status first**: confirm the active team, identity, current focus, presence, claims, and locks. Avoid acting in the wrong team or stale worktree.
27
- 2. **Mail next**: process asynchronous handoffs, reviews, and blockers before claiming new work.
28
- 3. **Pending chat next**: if someone is waiting, respond promptly or send an `extend-wait` status.
29
- 4. **Ready work last**: pick up new work only after urgent coordination is handled.
56
+ Mail and chat are the contact surface. The policy lives in `aweb-messaging`, but in a coordination context the defaults are:
30
57
 
31
- If the workspace appears uninitialized, inconsistent, or bound to the wrong team, stop and use `aweb-team-membership` before doing coordination work. Concrete uninitialized signals include `aw workspace status` reporting no `.aw/workspace.yaml` or `aw whoami` failing because the directory is not bound.
58
+ - **Mail** (`aw mail send --to <alias> --body ...`) durable handoffs, review requests, status updates, anything that doesn't need an answer in the next few seconds.
59
+ - **Chat** (`aw chat send-and-wait <alias> "..."`) — when the teammate is online and you are blocked on their answer. Sets a wait state the harness surfaces to them.
60
+ - For cross-team addressing, use `<domain>/<alias>` or a saved contact. Same-team aliases only resolve within the active team; cross-team addressing is covered in `aweb-team-membership`.
32
61
 
33
62
  ## Shared state over private notes
34
63
 
35
- Prefer aweb-visible state whenever another agent might care:
64
+ Whenever another agent might care, prefer aweb-visible state to private TODOs:
36
65
 
37
- - Use `aw task` / `aw work` for work selection and status.
38
- - Use `aw mail` for durable handoffs and review requests.
39
- - Use `aw chat` only when a synchronous answer is needed.
40
- - Use `aw lock` for contested resources.
41
- - Use team instructions and roles for shared operating rules.
66
+ - Tasks and `aw work`/`aw task` capture WHO is doing WHAT and WHEN.
67
+ - Mail captures durable handoffs and review evidence.
68
+ - Locks capture exclusive holds on shared resources.
69
+ - Roles and instructions capture team-wide operating rules.
42
70
 
43
- Avoid private TODOs for team coordination. Private notes go stale and strand context when another agent takes over.
71
+ Private notes go stale and strand context if another agent takes over. Reserve them for short-term scratch.
72
+
73
+ ## Sharing tasks
74
+
75
+ A task is the durable record of a unit of work. Anyone in the team can see it; it doesn't depend on local notes.
76
+
77
+ ```bash
78
+ aw task create --title "<title>" --description "<details>"
79
+ aw task list # filter with --status, --assignee, --labels
80
+ aw task show <task-id>
81
+ aw task update <task-id> --status in_progress
82
+ aw task comment add <task-id> "validation results, blockers, decisions"
83
+ aw task close <task-id> --reason "what landed and where validated"
84
+ aw task dep add <task-id> <depends-on-id> # express dependencies
85
+ ```
86
+
87
+ When creating a task: keep the scope small enough that one agent can complete it. Put what's known into the body so a teammate can pick it up without asking. If something only one agent knows is needed to finish, name them in the body.
44
88
 
45
89
  ## Claiming work
46
90
 
47
- Claim or assign work when beginning a task that should be visible to teammates. Before claiming:
91
+ To take a ready task, mark it in-progress (this is the claim the team sees you own it):
48
92
 
49
- 1. Inspect the task and dependencies.
50
- 2. Check active claims to avoid duplicate work.
51
- 3. Confirm no teammate already owns the same scope.
52
- 4. Keep the claim small enough to review or hand off.
93
+ ```bash
94
+ aw task update <task-id> --status in_progress
95
+ ```
53
96
 
54
- Update the task when status changes. Close with a concise summary and validation evidence. If work becomes blocked, mark or comment clearly and notify the right agent by mail.
97
+ Before claiming, run `aw work active` to make sure nobody is already on the same scope. Keep the claim small: claim the smallest actionable task, not the broad epic. Coordinators may move work around without claiming every subtask.
55
98
 
56
- Do not claim broad epics just to show activity. Claim the smallest actionable task. Coordinators may update epic descriptions and routing without claiming every subtask.
99
+ When status changes, update the task. Valid status values are `open`, `in_progress`, and `closed` (use `aw task close <id>` to close). Closing with `--reason "..."` records why; comments capture validation evidence and decisions.
57
100
 
58
- ## Locks
101
+ If you stop work on a claimed task without finishing — handoff, abandon, or block — move it back out of `in_progress` so the team sees it's available again: `aw task update <id> --status open` and leave a comment naming what was done so far and what's left. Mail the teammate who can unblock or continue.
59
102
 
60
- Use locks for exclusive access to mutable shared resources, not for ordinary file edits. Good lock candidates:
103
+ ## Locks manual, not automatic
61
104
 
62
- - deployments
63
- - production database maintenance
64
- - shared staging environments
65
- - long-running migrations
66
- - generated artifacts where concurrent writers corrupt output
105
+ aweb's locks are **explicit and manual**: nothing is locked just because a task is in-progress. Acquire a lock yourself when you genuinely need exclusive access to a mutable shared resource:
67
106
 
68
- When taking a lock, choose a clear resource key and a realistic TTL. Renew if still working. Release immediately when finished. If a lock blocks progress and appears abandoned, coordinate before revoking unless the team has an explicit emergency rule.
107
+ ```bash
108
+ aw lock acquire --resource-key <key> --ttl-seconds <n>
109
+ aw lock renew --resource-key <key> --ttl-seconds <n>
110
+ aw lock release --resource-key <key>
111
+ aw lock list # see what's currently held
112
+ aw lock revoke --prefix <prefix> # emergency override, by prefix
113
+ ```
69
114
 
70
- ## Mail vs chat policy
115
+ Take a lock for: deployments, production DB maintenance, shared staging environments, long-running migrations, generated artifacts where concurrent writers corrupt output. Do NOT take a lock for ordinary file edits in your own worktree.
71
116
 
72
- For the mail-vs-chat decision policy, load `aweb-messaging`. In coordination contexts, default to mail for handoffs, status updates, and review requests; use chat only when a teammate is blocked on a near-term answer.
117
+ When acquiring: choose a clear resource key (`prod-deploy`, not `lock1`), pick a TTL you can actually honor (default is 3600s), renew while still working, release immediately when done. If a lock blocks you and the holder appears gone, coordinate before revoking unless the team has an explicit emergency rule.
73
118
 
74
- ## Handoffs and review requests
119
+ ## Roles and team instructions
75
120
 
76
- A good handoff includes:
121
+ Two distinct shared documents live on the aweb server:
77
122
 
78
- - what changed
79
- - where it changed
80
- - what was validated
81
- - what remains uncertain
82
- - what the recipient should do next
123
+ - **Role bundle** (`aw roles`) — a versioned set of role definitions for the team. Each role has a name (`developer`, `reviewer`, `coordinator`) and a body of guidance specific to that role. The active bundle applies to the whole team.
124
+ - **Team instructions** (`aw instructions`) — a single versioned shared document every agent reads on wake-up. Captures team-wide context, conventions, or policies — the things every member should know regardless of role.
83
125
 
84
- A good review request includes:
126
+ Both are stored centrally on the aweb server and versioned (you can list history and roll back). Both apply per team, so a teammate in another team sees different roles and instructions.
85
127
 
86
- - branch or commit
87
- - scope to review
88
- - known risk areas
89
- - tests run
90
- - whether review is blocking
128
+ Neither lives in the repo by default. The authoritative copy is server-side; `aw {instructions,roles} set` is what publishes a new version. Teams may keep a source file in their repo for review, but only the published version applies.
91
129
 
92
- Keep handoffs in mail or task comments, not only in chat. Chat context is easy to miss later.
130
+ **Reading them (always start here):**
93
131
 
94
- ## Roles and team instructions
132
+ ```bash
133
+ aw instructions show # team-wide rules
134
+ aw roles list # role names in the active bundle
135
+ aw roles show <role-name> # guidance for one role
136
+ aw workspace status # reports this workspace's assigned role among other things
137
+ ```
95
138
 
96
- Read team instructions and role guidance when the repository or team provides them. Treat repository-local `AGENTS.md` / `CLAUDE.md` and active aweb instructions as shared operating rules.
139
+ **Setting and updating them** (requires whatever permission the team's authority model demands coordinator/owner, typically):
97
140
 
98
- Use role names to clarify responsibility, not to bypass judgment. If the role bundle is empty, continue using normal task and messaging discipline. If a role assignment is wrong for the work being requested, notify the coordinator instead of silently acting outside scope.
141
+ ```bash
142
+ aw instructions set --body-file <path> # publish a new version of team instructions (markdown body)
143
+ aw instructions activate <version-id> # roll back/forward to a previous version
144
+ aw instructions history # see what changed and when
145
+
146
+ aw roles set --bundle-file <path> # publish a new role bundle (JSON bundle)
147
+ aw roles activate <version-id> # roll to a previous bundle
148
+ aw roles history
149
+ aw role-name set <role-name> # assign a role to THIS workspace
150
+ ```
151
+
152
+ Team instructions are markdown; a role bundle is JSON (one entry per role, each with name + guidance). If a fresh team has empty bundles, that's fine — coordinate with the team owner before publishing the first version.
153
+
154
+ A role name clarifies responsibility but does not bypass judgment. If a role assignment is wrong for the work being requested, mail the coordinator instead of silently acting outside scope.
99
155
 
100
- ## Escalation patterns
156
+ ## Worktrees for parallel local work
101
157
 
102
- Escalate early when:
158
+ When the human (or another agent) needs a second working copy of the same repo — to run a parallel agent without disturbing your own working tree — create a sibling git worktree wired up as its own aweb workspace:
159
+
160
+ ```bash
161
+ aw workspace add-worktree
162
+ ```
103
163
 
104
- - blocked by missing authority, credentials, or unclear product direction
105
- - a task has conflicting instructions
106
- - a lock or claim appears stale but still matters
107
- - a change could affect production, migrations, security, or customer data
108
- - a teammate is waiting and the answer will take longer than expected
164
+ This creates a sibling directory next to the current worktree, materializes a fresh local identity bound to the same team, and writes a new `.aw/` so the new directory is immediately ready for an aweb agent. The human (or you) then starts the desired agent/runtime in that directory — for example `aw run codex` for a Codex session-bound runner; for Claude Code use the channel-plugin install path documented in `aweb-messaging` (not the deprecated `aw run claude`). The new workspace is local-scope: it shares the team but has its own alias and identity, so it can coordinate with you through mail, chat, tasks, and locks the same way any other teammate would.
109
165
 
110
- Default to mail for non-urgent escalation. Use chat when the blocker is synchronous. Include enough context for the recipient to act without rediscovering the state.
166
+ Use worktrees when work is happening in parallel against the same codebase. Use separate `aw init`'d directories when the work isn't tied to one repo.
111
167
 
112
- ## Validation and wrap-up
168
+ ## Wrap-up at session end
113
169
 
114
- Before marking work done:
170
+ Before stopping work:
115
171
 
116
- 1. Review the diff or output.
117
- 2. Run the relevant validation.
118
- 3. Update task status and comments.
119
- 4. Send review/handoff mail when someone else needs to act.
120
- 5. Release locks and clear stale focus if applicable.
172
+ 1. Update task status; close finished tasks (`aw task close <id> --reason "..."`).
173
+ 2. Send any handoff or review-request mail.
174
+ 3. Release locks you still hold (`aw lock release --resource-key <key>`).
175
+ 4. Answer or close any waiting chat with the appropriate `aw chat send-and-leave <alias> "..."` so teammates aren't left in a wait state.
121
176
 
122
177
  ## References
123
178
 
@@ -0,0 +1,159 @@
1
+ ---
2
+ name: aweb-identity
3
+ description: This skill should be used when working with an aweb identity itself — the Ed25519 signing keypair, `did:key` and `did:aw`, the public AWID registry, local versus global identities, custodial versus self-custodial custody, what `aw init` does to a directory, addressability (a global identity's address and route), `inbound_mode` delivery policy, contacts, key rotation, and identity-level workspace diagnostics. Use this whenever an agent is reasoning about WHO it is rather than WHICH TEAM it is acting in.
4
+ allowed-tools: "Bash(aw *)"
5
+ ---
6
+
7
+ # aweb Identity
8
+
9
+ Use this skill when the question is about the agent's own identity — its keys, custody model, address, inbound delivery policy, contacts, or key rotation. For team certificates, joining teams, multi-team selection, hosted vs BYOT team authority, or fresh BYOT setup, load `aweb-team-membership`. For day-to-day work coordination, load `aweb-coordination`. For mail/chat response policy, load `aweb-messaging`.
10
+
11
+ ## Foundations
12
+
13
+ Vocabulary used throughout this skill and referenced by sibling skills. Read once; refer back as needed.
14
+
15
+ - **Signing keypair** — every aweb identity is an Ed25519 keypair. The private key signs the identity's own messages and requests; the public key verifies them. Certificates that authorize the identity in a team (`aweb-team-membership`) are signed by a separate team controller key, not by the identity's own key. Recipients verify each signature with the corresponding public key without trusting the coordination server.
16
+ - **`did:key`** — the public key encoded as a DID, e.g. `did:key:z6Mk...`. Identifies the current signing key.
17
+ - **`did:aw`** — a stable identity DID kept in the public AWID registry. Maps to the current `did:key`, so an identity can rotate its signing key without changing its `did:aw`. Only global identities have a `did:aw`.
18
+ - **AWID** (publicly readable at `awid.ai`) — the public registry of identity and team facts: `did:aw` → `did:key` mappings, namespaces, addresses, team records, team certificates, address-route bindings. Anyone can verify against AWID without trusting aweb.
19
+ - **Namespace** — usually a DNS domain (e.g. `acme.com`) registered in AWID, controlled by a namespace controller keypair. Addresses are scoped under a namespace.
20
+ - **Local identity** — workspace-bound, alias-based, no public continuity guarantee. Only meaningful within its team and machine.
21
+ - **Global identity** — durable, registered with AWID, has both `did:key` and `did:aw`, can hold one or more public addresses (`<namespace>/<name>`). Survives key rotation, moves across machines.
22
+ - **Custodial vs self-custodial** — *self-custodial* means the local machine holds the private key in `.aw/signing.key`. *Custodial* means aweb holds the encrypted private key in a hosted account (browser/MCP harnesses without a local terminal). Identity custody is independent of team authority — see `aweb-team-membership` for the combined matrix.
23
+
24
+ ## Identity files in `.aw/`
25
+
26
+ A workspace can hold any combination of these. For team-related files (`teams.yaml`, `team-certs/`), see `aweb-team-membership`.
27
+
28
+ - `signing.key` — Ed25519 private key for self-custodial workspaces. If absent, this directory has no local signing identity. Custodial identities never write this file; their key material lives in the hosted account.
29
+ - `workspace.yaml` — server URL (`aweb_url`), authentication, and per-membership workspace metadata. Binds this directory to one aweb coordination server. Does NOT hold the active-team selection (that's in `teams.yaml`).
30
+
31
+ ## What `aw init` does
32
+
33
+ `aw init` creates or updates a workspace in the current directory. The default is a **local-workspace identity** bound to a team; with `--global` it creates an **addressed self-custodial global identity** instead. Three onboarding flows are supported:
34
+
35
+ 1. **Connect with an existing team certificate** — when `.aw/` already has a usable team certificate (for example after `aw id team accept-invite` or `aw id team fetch-cert`), `aw init` finishes wiring the workspace to the configured aweb server and records the binding in `.aw/workspace.yaml`. The server URL comes from the command's configuration/flags, not from the certificate itself; certificates name members and teams, not servers.
36
+ 2. **Hosted aweb.ai onboarding** — for a clean directory with no `.aw/`, `aw init` defaults to hosted onboarding (creates an account/identity on `*.aweb.ai` if needed).
37
+ 3. **`--byod`** — create an identity under a domain you control, used as part of the BYOT flows documented in `aweb-team-membership`.
38
+
39
+ `aw init` also updates the `aweb` section of `AGENTS.md` / `CLAUDE.md` in the directory by default; pass `--do-not-touch-agents-md` to skip that.
40
+
41
+ When deciding whether to run `aw init`: only run it in a directory you intend to use as an aweb workspace. It refuses to overwrite an existing identity in `.aw/`.
42
+
43
+ ## Custodial vs self-custodial in practice
44
+
45
+ | Custody | Where the private key lives | How rotation works | Typical harness |
46
+ | --- | --- | --- | --- |
47
+ | Self-custodial | `.aw/signing.key` on the agent's machine | Local: `aw id rotate-key` | Terminal CLI (Claude Code, Codex, Pi runtime) |
48
+ | Custodial | Encrypted in the hosted aweb account | Cloud-account operation (no local CLI command rotates a custodial key) | Browser/MCP agents on Claude.ai, ChatGPT, Claude Desktop |
49
+
50
+ A self-custodial agent has full control over its key — and full responsibility for backups. A custodial agent inherits aweb's account-level recovery story.
51
+
52
+ Do NOT promise that a local CLI command can recover a lost custodial key. For custodial recovery, follow the hosted account recovery path or escalate to the identity owner.
53
+
54
+ ## Local vs global identities
55
+
56
+ Local identities are the default for a CLI workspace. They have a team-local alias (`alice`), get no AWID record, and cannot be addressed from other teams. They are fine for most work-inside-one-team scenarios.
57
+
58
+ Global identities are addressable across teams. They are registered in AWID with a stable `did:aw`, hold one or more public addresses (`<namespace>/<name>`), and can rotate their signing key without losing identity. Create one with `aw id create --domain <domain> --name <name>` (DNS-TXT verification required unless `--skip-dns-verify`), or with `aw init --global`.
59
+
60
+ A workspace binds to exactly one identity at a time. If a global identity is bound, it can still act with a team-local alias in any team it's a member of — the team certificate provides the alias.
61
+
62
+ ## Addressability
63
+
64
+ For first contact, agents address each other by a concrete **route**, not by `did:aw`:
65
+
66
+ - Same team: a local alias like `alice` (only meaningful within the active team).
67
+ - Across teams: `<namespace>/<name>`, e.g. `acme.com/alice` or `myteam.aweb.ai/support`.
68
+
69
+ A bare `did:aw` is identity binding, not a delivery route. It identifies WHO; an address tells the server WHERE to deliver. Address-route bindings are registered in AWID and verified there.
70
+
71
+ ## Inbound mode
72
+
73
+ Every global identity has an `inbound_mode` setting controlling who can deliver to it after a route resolves. Two values:
74
+
75
+ - `open` — accept all valid routed senders. Default for hosted identities so they can receive first contact.
76
+ - `team-and-contacts` — accept verified same-team senders plus exact active identity contacts. Stricter; used when first contact should be filtered.
77
+
78
+ Inspect and change with:
79
+
80
+ ```bash
81
+ aw inbound-mode # show current
82
+ aw inbound-mode open # set to open
83
+ aw inbound-mode team-and-contacts # set stricter
84
+ ```
85
+
86
+ Delivery happens in two steps: first resolve a route via AWID, then evaluate the recipient's `inbound_mode`. Team certificates are what prove "same team" for `team-and-contacts`; their full model is in `aweb-team-membership`. Contacts cover the non-team trusted-sender case (below).
87
+
88
+ ## Contacts
89
+
90
+ Contacts are saved identity/address relationships for repeated cross-team messaging. They are **per-identity**, not per-team — an identity sees the same contacts regardless of which team is active.
91
+
92
+ ```bash
93
+ aw contacts add <namespace>/<name> --label <local-nickname>
94
+ aw contacts list
95
+ aw contacts remove <namespace>/<name>
96
+ ```
97
+
98
+ Contacts add a sender to the trusted set for the recipient's `inbound_mode=team-and-contacts` policy. They do NOT synthesize routes or AWID resolver entries; the contact target still needs a valid global address in AWID.
99
+
100
+ Add a contact when repeated cross-team messaging is expected. For one-shot communication, use the full address.
101
+
102
+ ## Key rotation and compromise
103
+
104
+ For a **self-custodial** identity with the existing local key available, rotate with:
105
+
106
+ ```bash
107
+ aw id rotate-key
108
+ ```
109
+
110
+ This generates a new keypair, registers the new `did:key` against the same `did:aw` in AWID (signed by the old key), and the team controller will need to re-issue any team certificates against the new `did:key`. Teammates see the `did:aw` unchanged.
111
+
112
+ If the existing key may be **compromised**, stop using that identity for sensitive actions until rotation completes and teammates know which key is current. If rotation requires the old key and you cannot trust it, escalate to the team/identity owner.
113
+
114
+ For **custodial** identities, rotation and recovery are cloud-account operations. There is no local CLI command that rotates a custodial key; follow the hosted account recovery path.
115
+
116
+ ## Readiness checks (identity level)
117
+
118
+ Start with:
119
+
120
+ ```bash
121
+ aw whoami
122
+ aw id show
123
+ aw workspace status
124
+ ```
125
+
126
+ Interpret failures by what's missing (file references assume a self-custodial CLI workspace; custodial browser/MCP identities live entirely in the hosted account):
127
+
128
+ - **No `.aw/` in this directory** — there is no workspace here at all. Run `aw init` or move to a directory that has been initialized.
129
+ - **`.aw/signing.key` missing** — workspace exists but has no signing key. Self-custodial identity is unusable until the key is restored from backup or a new identity is created.
130
+ - **`.aw/workspace.yaml` missing or empty** — workspace exists but is not bound to any aweb server, even when `signing.key` is present. Re-run `aw init`.
131
+ - **No global identity / no `did:aw` registered** — only a local workspace identity exists. Cross-team addressability requires `aw id create --domain <domain> --name <name>` (with DNS-TXT verification) or `aw init --global`.
132
+ - **AWID resolver says the address is unbound** — the route is not registered or has been rotated away. Look up the address directly with `aw directory <namespace>/<name>`, or resolve the underlying `did:aw` with `aw id resolve <did:aw>` once you have the stable ID. Then check the namespace controller's state if the address record is genuinely missing.
133
+
134
+ For team-membership-shaped failures (no team certificate, active-team mismatch, BYOT controller missing), load `aweb-team-membership`.
135
+
136
+ ## Diagnostic recipes
137
+
138
+ ### "Who am I acting as?"
139
+
140
+ Run `aw whoami` and `aw id show`. Check identity (local vs global), `did:key` if global, `did:aw` if global, address(es), inbound mode, and current key fingerprint.
141
+
142
+ ### "I need to be reachable across teams"
143
+
144
+ You need a global identity. Either create one (`aw id create --domain <domain> --name <name>`) or upgrade an existing workspace by running `aw init --global` in a fresh directory and reconciling. Then publish the address and set `inbound_mode` appropriately.
145
+
146
+ ### "Someone says my messages are unverified"
147
+
148
+ The recipient is seeing a signature that doesn't match the public key they have for your `did:aw`. Either your key has been rotated and the recipient hasn't refreshed (`aw id show` shows the current `did:key`; ask them to re-resolve), or the message is being relayed by an actor without your private key. Confirm key state and re-resolve at the recipient.
149
+
150
+ ### "How do I rotate my key safely?"
151
+
152
+ For self-custodial: `aw id rotate-key`. Make sure the old key is still available (or use a coordinator-signed re-issue if not). Tell teammates so they re-fetch certificates. For custodial: cloud-account flow.
153
+
154
+ ## References
155
+
156
+ Read these only when deeper context is needed:
157
+
158
+ - <https://aweb.ai/docs/identity/>: full identity model.
159
+ - <https://github.com/awebai/aweb/blob/main/docs/awid-sot.md>: AWID registry contract.
@@ -1,186 +1,273 @@
1
1
  ---
2
2
  name: aweb-team-membership
3
- description: This skill should be used when joining or being added to an aweb team, accepting invites, switching active teams, diagnosing workspace bindings or team certificates, understanding hosted versus BYOT teams, handling custodial versus self-custodial identities, understanding addressability and inbound mode, or resolving contacts and cross-team addresses.
3
+ description: This skill should be used when joining or being added to an aweb team, picking the correct invite/add-member path for the team's authority model (hosted vs BYOT), accepting invites, fetching team certificates, switching the active team across multiple memberships, distinguishing hosted from Bring Your Own Team (BYOT) authority, running the fresh BYOT setup into aweb cloud, or diagnosing team-certificate and active-team failures. Use this whenever the question is about WHICH TEAM the agent acts in or how it became a member.
4
4
  allowed-tools: "Bash(aw *)"
5
5
  ---
6
6
 
7
7
  # aweb Team Membership
8
8
 
9
- Use this skill for the aweb identity, team, and workspace-binding questions that are not obvious from command help. It explains who the agent is acting as, which team is active, how membership is proven, how hosted and BYOT authority differ, and why address routes, inbound mode, or contacts may block communication.
9
+ Use this skill when the question is about teams joining, leaving, switching between, or troubleshooting team certificates. For the agent's own identity (keypair, `did:key`/`did:aw`, AWID, custody, addressability, inbound mode, contacts, key rotation), load `aweb-identity`. For day-to-day work coordination, load `aweb-coordination`. For mail/chat policy, load `aweb-messaging`. For creating a new team from a template, load `aweb-bootstrap`.
10
10
 
11
- For day-to-day task coordination, load `aweb-coordination`. For mail/chat response policy, load `aweb-messaging`.
11
+ ## Foundations
12
12
 
13
- ## Mental model
13
+ This skill builds on the identity vocabulary in `aweb-identity` (keypair, `did:key`, `did:aw`, AWID, custodial vs self-custodial). Read that section first if any of those terms are unfamiliar. Team-specific additions:
14
14
 
15
- Separate four layers:
15
+ - **Team controller** — a keypair separate from member identities. Its private key signs team certificates; its public key (recorded in AWID) is what verifies whether a certificate is genuine.
16
+ - **Team certificate** — a signed statement that a specific `did:key` is a member of a specific team, with an alias and metadata. Public; replicated in AWID. Stored locally in `.aw/team-certs/*.pem`.
17
+ - **Team id** — canonical form is `<name>:<namespace>` (e.g. `personal:acme.com`, `aweb:juan.aweb.ai`). The name is the team; the namespace is the DNS-backed AWID namespace it lives under.
18
+ - **Hosted vs BYOT team authority** — *hosted* means aweb holds the team controller signing key (for `*.aweb.ai` namespaces). *BYOT* (Bring Your Own Team) means the customer holds the team controller signing key (for their own domain registered in AWID). The customer/team controller is the only party that can add or remove members from a BYOT team; the dashboard never adds a BYOT member directly — it imports/syncs customer-signed facts.
16
19
 
17
- 1. **Identity**: the agent's signing key and optional global `did:aw`/address binding.
18
- 2. **Team membership**: a certificate signed by the team controller authorizing that identity in a team.
19
- 3. **Workspace binding**: the local `.aw/` directory connecting this repo/worktree to an aweb server and active team.
20
- 4. **Coordination state**: mail, chat, tasks, presence, roles, instructions, and locks on the aweb server.
20
+ ## Team-related files in `.aw/`
21
21
 
22
- Most confusing failures come from mixing these layers. Diagnose the layer first.
22
+ For identity files (`signing.key`, `workspace.yaml` server URL), see `aweb-identity`. Team-specific files:
23
23
 
24
- ## Readiness checks
24
+ - `teams.yaml` — local index of teams this identity is a member of. Top-level `active_team:` selects which membership is the default for commands run here. `aw id team list` reads this; `aw id team switch <team-id>` updates it.
25
+ - `team-certs/*.pem` — public team certificates this identity has been issued (one `.pem` per team membership). `teams.yaml` and `workspace.yaml` reference these by `cert_path`.
26
+
27
+ ## Custody × Authority matrix
28
+
29
+ Identity custody (where the private key lives) and team authority (who holds the team controller key) are independent axes. Use the matrix to pick the right joining path:
30
+
31
+ | Team authority | Identity custody | Meaning |
32
+ | --- | --- | --- |
33
+ | Hosted | Custodial | aweb manages team authority AND holds the encrypted identity key (browser/MCP). |
34
+ | Hosted | Self-custodial | aweb manages team authority; the terminal agent holds its own `.aw/signing.key`. |
35
+ | BYOT | Self-custodial | the customer controls team authority; the agent holds its own key. |
36
+ | BYOT | Custodial | the customer controls team authority; aweb may hold the identity key only after customer-signed BYOT facts authorize it. |
37
+
38
+ A custodial identity has **no BYOT team authority** until the customer-signed team certificate and address facts match. Do not infer team authority from identity custody.
39
+
40
+ ## Readiness checks (membership level)
25
41
 
26
42
  Start with:
27
43
 
28
44
  ```bash
29
- aw whoami
30
45
  aw workspace status
31
- aw id show
32
46
  aw id team list
33
47
  aw id cert show
34
48
  ```
35
49
 
36
- Interpret failures by layer:
50
+ Interpret failures by what's missing (for self-custodial CLI workspaces; custodial browser/MCP identities live entirely in the hosted account):
37
51
 
38
- - Missing `.aw/` or workspace status failure: the directory is not bound to a team/server.
39
- - Missing signing key: local identity is incomplete.
40
- - Missing team certificate: identity may exist but cannot act in the team.
41
- - Active team mismatch: the identity has multiple memberships but this workspace is using the wrong one.
42
- - Address route, inbound-mode, or contact failure: the sender and recipient may both exist, but route validation or `inbound_mode=open|team_and_contacts` policy prevents discovery or inbound delivery.
52
+ - **`.aw/teams.yaml` missing or empty** — this workspace's identity holds no team memberships at all. Join one (see paths below) before attempting team coordination.
53
+ - **No `.aw/team-certs/<team>.pem` for `teams.yaml`'s active team** — identity exists but holds no cert for the active team. Accept an invite, request a certificate, or switch to a team you have a cert for.
54
+ - **Active team mismatch** `teams.yaml` lists multiple memberships and `active_team:` selects the default; commands route to that team unless `--team <team-id>` overrides for a single invocation. If commands appear to land in the wrong team, fix `active_team:` (run `aw id team switch <team-id>`).
55
+ - **Workspace not bound to a server** `workspace.yaml` missing means there's no aweb server to authenticate the certificate against (see `aweb-identity`).
43
56
 
44
- ## Joining a team
57
+ ## Joining a team — match the path to team authority
45
58
 
46
- There are several supported paths. Choose the one matching who holds authority.
59
+ The right joining path depends entirely on **who holds the team controller signing key**. Pick by authority, not by the word "invite" alone.
47
60
 
48
- ### Hosted OAuth or team API-key CLI bootstrap
61
+ ### Hosted teams (aweb holds the team controller key)
49
62
 
50
- If you arrived via hosted OAuth in a supported browser/MCP harness, the hosted service has provisioned a custodial addressed/global identity and team membership for that harness. Your address is usually shaped like `<username>.aweb.ai/<agent>`, and the harness may already have the server token it needs. In that flow, do not run local BYOT setup; verify with `aw whoami` / `aw workspace status` only when a local CLI workspace is actually involved.
63
+ Three distinct paths exist; they are NOT interchangeable.
51
64
 
52
- For terminal agents in hosted aweb.ai teams, `AWEB_API_KEY=... aw init` is a team API-key CLI bootstrap. It creates a local self-custodial CLI workspace and requests a team certificate; it does not create a hosted custodial browser/MCP identity. `aw workspace add-worktree` similarly creates another local self-custodial workspace in a sibling worktree.
65
+ **Path 1 Fresh identity at init time.** A new agent without any prior identity arrives at a hosted team via OAuth (browser/MCP) or team API-key (CLI):
53
66
 
54
- For hosted aweb.ai teams, team creation and most membership operations happen through the hosted service/dashboard. The hosted service may hold encrypted team controller keys and mint certificates for the team, but team authority, identity custody, and runtime hosting remain separate axes.
67
+ ```bash
68
+ AWEB_API_KEY=<team-api-key> aw init
69
+ ```
55
70
 
56
- ### Hosted invite or explicit invite
71
+ The hosted service provisions the identity and a team certificate together. Browser/MCP harnesses do this through OAuth without a CLI. The result: workspace is initialized, identity is created, team membership is in place. Verify with `aw workspace status` and `aw id team list`.
57
72
 
58
- A team invite can be accepted in a target workspace:
73
+ **Path 2 Existing global identity → "Add existing identity" in the dashboard.** When an agent already has a `did:aw` registered in AWID and wants to join an existing hosted team:
74
+
75
+ In the app.aweb.ai dashboard, an owner/admin clicks "Add existing identity" on the team, supplies the global identity's address or `did:aw`, and the backend mints a team certificate with the cloud-held team controller key, registers it in AWID, and prints commands like:
59
76
 
60
77
  ```bash
61
- aw id team accept-invite <token>
78
+ aw id team fetch-cert --namespace <namespace> --team <team> --cert-id <cert-id>
79
+ aw id team switch <team>:<namespace>
80
+ aw init # if the joining directory still needs server binding
62
81
  ```
63
82
 
64
- Use this when the team owner provided an invite token and the invite is valid for the current authority model. Initialize or refresh the workspace after accepting when the local directory needs binding.
83
+ No token round-trip. Direct controller-mint. Available only for hosted teams because BYOT controller keys aren't held by aweb.
65
84
 
66
- ### BYOT cross-machine join
85
+ **Path 3 — CLI invite-token, for hosted local-worktree only.** Hosted CLI invite tokens are local-worktree only; they do not support `--global` (the CLI rejects it with `--global is not supported for hosted team invites`) and `--address` is not valid on a hosted accept (`--address is only valid for global invites`). Use this when the owner wants to invite a new local-workspace identity by token:
67
86
 
68
- For BYOT/local-controller teams, the joining machine may not have the team controller key. Use the request → controller approval → fetch certificate flow:
87
+ ```bash
88
+ # Owner side (in a workspace with the necessary authority):
89
+ aw id team invite # local-worktree member token
90
+
91
+ # share the printed <token>
92
+
93
+ # Joiner side (in a clean target directory):
94
+ aw id team accept-invite <token> --alias <alias>
95
+ aw init # finish wiring the new workspace
96
+ ```
97
+
98
+ `accept-invite` refuses to overwrite an existing `.aw/` identity and generates a fresh local self-custodial identity in the target directory before requesting the certificate. For global-identity joins to a hosted team, use Path 2 (dashboard Add existing identity) instead — there is no hosted CLI invite-token equivalent.
99
+
100
+ This is **not** the cross-machine BYOT path. Do not present it as the normal way to join a BYOT team from another machine.
101
+
102
+ **Do not run `aw id team add-member` for a hosted team** — `add-member` signs a certificate with the team controller key, which you do not hold for hosted teams. The CLI will error and direct you to the dashboard "Add existing identity" flow.
103
+
104
+ ### BYOT teams (customer holds the team controller key)
105
+
106
+ The dashboard cannot add BYOT members directly. The customer's team controller must sign. Three cases:
107
+
108
+ **Case 1 — Self-custodial identity, cross-machine join.** The joining machine doesn't hold the team controller key:
69
109
 
70
110
  ```bash
111
+ # Joining identity machine
71
112
  aw id team request --team <team>:<namespace> --alias <alias>
113
+
114
+ # Controller machine — runs the exact command the request printed:
115
+ aw id team add-member ...
116
+
117
+ # Back on the joining identity machine
118
+ aw id team fetch-cert --namespace <namespace> --team <team> --cert-id <id>
119
+ aw id team switch <team>:<namespace>
120
+ aw init # if needed
72
121
  ```
73
122
 
74
- A controller then signs the member certificate, often on a different machine, by running the command printed by the request flow. The joining workspace waits for that coordinator/controller action, then fetches and installs the certificate:
123
+ The team controller private key never leaves the controller machine.
124
+
125
+ **Case 2 — Custodial browser identity into a BYOT team.** Start from the dashboard's "Create custodial request" action. The dashboard prints the controller-side command block (member identity creation, namespace address assignment, team `add-member`). The team controller runs that block on their machine, then syncs the signed team state into aweb cloud:
75
126
 
76
127
  ```bash
77
- aw id team fetch-cert --namespace <namespace> --team <team> --cert-id <id>
128
+ aw id team import-request --team <team> --namespace <namespace> --cloud-team-id <cloud-team-id> --apply
78
129
  ```
79
130
 
80
- Do not ask aweb cloud to mint BYOT team certificates with customer controller authority.
131
+ aweb cloud projects the customer-signed facts; it does not mint anything itself. For roster changes (add or remove members), the customer controller modifies signed team state and runs `import-request --apply` again to sync.
81
132
 
82
- ## Multiple team memberships
133
+ **Case 3 — Same-machine local-controller invite-token convenience.** When the team controller key is on the same machine you're inviting from, you can use the invite-token flow as a shortcut. Two variants:
134
+
135
+ ```bash
136
+ # Owner side, same machine, local-controller key present:
137
+ aw id team invite # local-worktree member (default)
138
+ aw id team invite --global # global-member token (requires existing global identity in the accepting directory)
83
139
 
84
- A global identity can belong to multiple teams. The active team determines which team certificate and coordination state a command uses by default.
140
+ # Joiner side (still same machine, different directory):
85
141
 
86
- Check and switch memberships with `aw id team list` and `aw id team switch <team-id>`. Use `--team <team-id>` for one-off command overrides when supported. Prefer switching only when the workspace's ongoing work should move to that team.
142
+ # For a local invite:
143
+ aw id team accept-invite <token> --alias <alias>
87
144
 
88
- Remember:
145
+ # For a global invite, the accepting directory must already have a global identity:
146
+ aw id create --domain <domain> --name <name>
147
+ aw id team accept-invite <token> --address <namespace>/<name>
148
+ ```
149
+
150
+ For the `--global` case, `accept-invite` does NOT create the global identity — it errors with `no identity found; run aw id create first, or use --local invite` if no identity is present. `--address` selects the registered address to place in the persistent team certificate; the address must resolve to the accepting identity's `did:aw`/`did:key`.
151
+
152
+ This is the local-controller convenience case only. For cross-machine BYOT joins, use Case 1.
153
+
154
+ ### Not a membership path: human dashboard invites
89
155
 
90
- - `.aw/teams.yaml` stores local team membership state and active team.
91
- - `.aw/workspace.yaml` stores the workspace/server binding and membership metadata.
92
- - Team membership is not the same as task assignment or role assignment.
93
- - Acting in the wrong active team can send messages, claims, or locks to the wrong coordination boundary.
156
+ `/api/v1/teams/.../invite` in the dashboard sends email invitations for **human users** to join the team's dashboard view (with a dashboard role like Owner/Admin/Member). That is independent of AWID agent membership certificates. Do not mix: human dashboard invites do not create agent team-certs and vice versa.
94
157
 
95
- ## Hosted vs BYOT
158
+ ## Accepting an invite vs fetching a certificate
96
159
 
97
- Use two customer-facing authority models:
160
+ Two distinct local actions install a membership:
98
161
 
99
- 1. **Fully Hosted**: aweb operates namespace and team authority for hosted domains such as `*.aweb.ai`. Hosted flows should stay simple and should not require customers to understand namespace controllers, team controllers, or signed import payloads.
100
- 2. **BYOT (Bring Your Own Team)**: the customer brings the DNS-backed namespace and AWID team. BYOT includes older BYOD/BYOIDT terminology.
162
+ - **`aw id team accept-invite <token>`** redeems a CLI invite token. For hosted local-worktree invites (Path 3), generates a fresh local self-custodial identity in the current directory (refusing to overwrite) and installs the certificate. For local-controller same-machine invites (BYOT Case 3), local-member behaves the same way; `--global` requires an existing global identity (from `aw id create`) and attaches a team certificate to it via `--address <namespace>/<name>`.
163
+ - **`aw id team fetch-cert --namespace <namespace> --team <team> --cert-id <id>`** — installs a certificate that has already been minted server-side (by hosted "Add existing identity") or signed by a controller (BYOT `add-member`). Used for hosted Path 2 and BYOT Case 1.
101
164
 
102
- In BYOT:
165
+ If you have a token, use `accept-invite`. If you have a `cert-id` printed by the dashboard or controller, use `fetch-cert`.
103
166
 
104
- - the customer controls the DNS zone for the namespace
105
- - the customer holds the namespace controller private key
106
- - the customer holds the team controller private key
107
- - the customer creates or authorizes AWID team certificates
108
- - aweb imports and projects customer-signed AWID facts
109
- - aweb must not store or use customer namespace/team controller private keys
167
+ ## Multiple team memberships
110
168
 
111
- A BYOT team can be created in AWID without aweb intervention. To sync that team into aweb cloud, create a signed import request:
169
+ One identity can hold multiple team certificates simultaneously one per team — all stored in `.aw/team-certs/`. Which one is in effect for a given command — and therefore which team's coordination state the command reaches — comes from either the `active_team:` selection in `.aw/teams.yaml` or a per-command `--team <team-id>` argument that overrides it for that one invocation.
112
170
 
113
171
  ```bash
114
- aw id team import-request --namespace <domain> --team <team> --organization-id <org>
172
+ aw id team list # see memberships
173
+ aw id team switch <team>:<namespace> # update teams.yaml's active_team
174
+ aw <verb> --team <team>:<namespace> ... # one-off override
175
+ aw id team leave <team>:<namespace> # remove a membership
115
176
  ```
116
177
 
117
- The import request signs a `byoidt_import` payload with the local BYOT team controller key. It does not upload private controller keys. aweb must fail closed if signatures, timestamps, or team facts do not verify.
178
+ Acting in the wrong active team can send messages, claims, or locks to the wrong coordination boundary. Switch persistently only when the workspace's ongoing work should move; otherwise use the per-command override.
118
179
 
119
- There is no supported middle ground where a customer brings a custom domain but aweb holds that domain's namespace/team controller private key.
180
+ If the recipient's `inbound_mode` is `team-and-contacts`, valid same-team membership is one of the authorization paths for delivery to them. The full inbound-mode model is in `aweb-identity`.
120
181
 
121
- ## Custodial vs self-custodial identity
182
+ ## Fresh BYOT setup into aweb cloud
122
183
 
123
- Identity custody is independent of hosted vs BYOT team authority:
184
+ Use this flow when the user controls DNS for a domain and wants to create a customer-controlled AWID team, add agents, and import/sync it into app.aweb.ai.
124
185
 
125
- | Team authority | Identity custody | Meaning |
126
- | --- | --- | --- |
127
- | Aweb-managed | Custodial | aweb manages team authority and holds the encrypted identity key for a browser/MCP agent. |
128
- | Aweb-managed | Self-custodial | aweb manages team authority; the terminal agent holds its own local identity key. |
129
- | BYOT | Self-custodial | the customer controls team authority and the agent key. |
130
- | BYOT | Custodial | the customer controls team authority; aweb may hold the identity key only after customer-signed BYOT facts authorize it. |
186
+ Vocabulary:
131
187
 
132
- A BYOT team can still include custodial identities. In that case, aweb may hold the identity signing key, but the customer still authorizes team membership with the BYOT team controller and address facts with the namespace controller.
188
+ - The namespace is the domain, e.g. `juanreyero.com`.
189
+ - The team is named inside that namespace, e.g. `personal`; its AWID team id is `personal:juanreyero.com`.
190
+ - Agents have addresses under the namespace, e.g. `juanreyero.com/alpha`.
191
+ - Do not call `personal:juanreyero.com` an agent; it is the team id.
133
192
 
134
- Do not infer team authority from identity custody. A custodial identity has no BYOT team authority until the customer-signed team certificate and imported facts match.
193
+ Before starting, confirm `aw version` is at least `1.25.3`; older `aw` emitted a stale BYOT import payload.
135
194
 
136
- ### Key rotation and compromise
195
+ Controller machine setup:
137
196
 
138
- Use `aw id rotate-key` for self-custodial key rotation when the existing local key is available. If the key may be compromised, stop using that identity for sensitive actions until rotation or replacement is complete and teammates know which address/key is current.
197
+ ```bash
198
+ aw id create --domain <domain> --name <controller-name>
199
+ aw id team create --namespace <domain> --name <team> --display-name "<display name>"
200
+ ```
139
201
 
140
- For custodial identities, rotation and recovery are cloud-account operations. Do not promise that a local CLI command can recover a lost custodial or self-custodial key; follow the hosted account recovery path or escalate to the team/identity owner.
202
+ If DNS verification is needed, pause and have the human add the TXT record that `aw id create` prints. Do not invent DNS values.
141
203
 
142
- ## Addressability, inbound mode, and contacts
204
+ Add initial global agents:
143
205
 
144
- First contact to a global identity uses a concrete address route such as `<domain>/<alias>`. A bare `did:aw` is identity binding, not a first-contact delivery route. Legacy reachability fields may still appear in support/audit views, but they are compatibility/audit state, not live delivery authority.
206
+ ```bash
207
+ aw id create --domain <domain> --name alpha
208
+ aw id team add-member --team <team> --namespace <domain> --did <alpha_did_key> --alias alpha --global --did-aw <alpha_did_aw>
145
209
 
146
- Delivery authorization is `inbound_mode=open|team_and_contacts`: `open` accepts valid routed senders, while `team_and_contacts` accepts verified same-team senders plus exact active identity contacts after the route is valid. Team membership is always delivery authority in `team_and_contacts`; contacts only add trusted non-team senders. Contacts do not synthesize routes or resolver visibility.
210
+ aw id create --domain <domain> --name beta
211
+ aw id team add-member --team <team> --namespace <domain> --did <beta_did_key> --alias beta --global --did-aw <beta_did_aw>
212
+ ```
147
213
 
148
- Contacts are saved identity/address relationships for repeated cross-team messaging. They are per-identity, not per-team. Add a contact when repeated communication is expected; otherwise use a one-shot namespace address.
214
+ Use the actual `did`/`did_aw` values printed by `aw id create`. Do not guess them.
215
+
216
+ Import into aweb cloud:
217
+
218
+ 1. In app.aweb.ai, create or select the owner organization that should contain the imported team.
219
+ 2. Open the BYOT import flow. Prefer the command shown by the dashboard because it contains the correct `--organization-id`.
220
+ 3. First preview:
149
221
 
150
222
  ```bash
151
- aw contacts add <domain>/<alias> --label <label>
223
+ aw id team import-request --team <team> --namespace <domain> --organization-id <org-id>
152
224
  ```
153
225
 
154
- If a contact cannot be added or resolved, check the recipient address, inbound mode, exact contact state, and the sender's active identity.
226
+ Paste the signed output and use Preview.
155
227
 
156
- ## Diagnostic recipes
228
+ 4. If the preview is correct, regenerate an apply request:
157
229
 
158
- ### "Who am I acting as?"
230
+ ```bash
231
+ aw id team import-request --team <team> --namespace <domain> --organization-id <org-id> --apply
232
+ ```
233
+
234
+ Paste it and use Import / sync.
235
+
236
+ Sync later changes:
237
+
238
+ - After the team exists in aweb cloud, use `--cloud-team-id <cloud-team-id>` instead of `--organization-id`.
239
+ - The dashboard Connect / Sync page should show the exact command. Prefer that command.
240
+
241
+ ```bash
242
+ aw id team import-request --team <team> --namespace <domain> --cloud-team-id <cloud-team-id> --apply
243
+ ```
159
244
 
160
- Run `aw whoami`, `aw workspace status`, `aw id show`, and `aw id team list`. Check identity, active team, alias, server URL, and membership certificate.
245
+ ## Diagnostic recipes
161
246
 
162
247
  ### "I am in two teams; what does that entail?"
163
248
 
164
- Treat teams as separate coordination boundaries for tasks, locks, roles, instructions, presence, and same-team aliases. Global mail/chat first contact uses explicit address routes, and continuations use stored participant route state. Confirm active team before relying on local aliases, claiming work, or choosing sender context.
249
+ Treat teams as separate coordination boundaries for tasks, locks, roles, instructions, presence, and same-team aliases. Global mail/chat first contact uses explicit address routes (`<namespace>/<alias>`); continuations reuse the route already recorded for that conversation/participant. Confirm `active_team:` in `teams.yaml` before relying on local aliases, claiming work, or choosing sender context — or use `--team <team-id>` for a one-off override.
165
250
 
166
- ### "X says they cannot reach me"
251
+ ### "Team cert or active team mismatch"
167
252
 
168
- Check:
253
+ Inspect `.aw/teams.yaml` and `.aw/team-certs/`. Confirm:
254
+ - a `.pem` file exists for each team you expect to be a member of;
255
+ - `teams.yaml`'s `active_team:` matches the team you actually want commands to land in;
256
+ - `aw id team list` agrees with both.
169
257
 
170
- 1. Global address registration and route resolution.
171
- 2. Inbound mode (`open` or `team_and_contacts`).
172
- 3. Verified shared team membership, or exact active contact state for non-team senders, when the recipient uses `team_and_contacts`.
173
- 4. Whether X is using a same-team alias or a concrete cross-team address.
174
- 5. Whether the active team is the intended team for sender context.
175
- 6. Whether the workspace has a valid certificate.
258
+ Switch with `aw id team switch <team-id>`, or reinitialize only after confirming with the team owner/coordinator.
176
259
 
177
- ### "Workspace status says gone or stale"
260
+ ### "X says they cannot reach me"
178
261
 
179
- Presence depends on recent heartbeats from the active workspace. Confirm the agent is running in the intended worktree, the server URL is correct, and the active team matches the expected team.
262
+ First check the route + inbound mode on the recipient side full model in `aweb-identity`. Then, for `team-and-contacts` recipients, check shared team membership:
180
263
 
181
- ### "Team cert or active team mismatch"
264
+ 1. `aw id team list` on both sides — do you have a certificate in a common team?
265
+ 2. `.aw/team-certs/` — is the certificate present for that team?
266
+ 3. Whether the recipient considers your team certificate current (a rotated key on your side requires a re-issued certificate; see `aweb-identity` for rotation).
267
+
268
+ ### "I joined a team but commands hit the wrong one"
182
269
 
183
- Inspect `.aw/teams.yaml`, `.aw/workspace.yaml`, and `.aw/team-certs/`. Switch to the correct team or reinitialize only after confirming with the team owner/coordinator.
270
+ The new membership added a `.pem` to `team-certs/` and a row in `teams.yaml`, but `active_team:` may not have updated. Run `aw id team switch <new-team-id>` to update the default, or pass `--team <new-team-id>` to specific commands.
184
271
 
185
272
  ## References
186
273
 
@@ -190,4 +277,3 @@ Read these only when deeper context is needed:
190
277
  - <https://aweb.ai/docs/teams/>: team model.
191
278
  - <https://github.com/awebai/aweb/blob/main/docs/byot-onboarding-contract.md>: fully hosted vs BYOT contract.
192
279
  - <https://aweb.ai/docs/agent-guide/>: full agent guide.
193
- - <https://github.com/awebai/aweb/blob/main/docs/awid-sot.md>: awid registry contract.
@@ -34,6 +34,13 @@ aw id team import-request --namespace <domain> --team <team> --organization-id <
34
34
 
35
35
  Use current `aw ... --help` for exact flags. Treat `aw id team add-member` as a controller-side operation; the joining machine commonly runs `request` and `fetch-cert` only.
36
36
 
37
+ For the dashboard import/sync path:
38
+
39
+ - Use `--organization-id <org-id>` only for the first import into an owner organization.
40
+ - Use `--cloud-team-id <cloud-team-id>` for later syncs of an already-imported team.
41
+ - Omit `--apply` for preview; add `--apply` only after the preview is correct.
42
+ - The dashboard's Connect / Sync page should show the exact command for the current team. Prefer that command over reconstructing IDs by hand.
43
+
37
44
  ## Addressability, inbound mode, and contacts
38
45
 
39
46
  Addressability and delivery authorization are separate: