@awebai/pi 0.1.15 → 0.1.17

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.
package/dist/index.js CHANGED
@@ -5904,6 +5904,42 @@ function escapeJSON3(s) {
5904
5904
  return result;
5905
5905
  }
5906
5906
 
5907
+ // ../channel-core/dist/local_aw.js
5908
+ import { execFile } from "node:child_process";
5909
+ import { promisify } from "node:util";
5910
+ var execFileAsync = promisify(execFile);
5911
+ function createLocalAWDecryptProvider(options) {
5912
+ const awCommand = options.awCommand || process.env.AW_BIN || "aw";
5913
+ return {
5914
+ async mailMessage(messageID) {
5915
+ const id = messageID.trim();
5916
+ if (!id)
5917
+ return null;
5918
+ const { stdout } = await execFileAsync(awCommand, ["mail", "show", "--message-id", id, "--json"], { cwd: options.workdir, timeout: 15e3, maxBuffer: 1024 * 1024 });
5919
+ const payload = parseJSONOutput(stdout);
5920
+ return (payload.messages || []).find((msg) => msg.message_id === id) || null;
5921
+ },
5922
+ async chatMessage(sessionID, messageID) {
5923
+ const session = sessionID.trim();
5924
+ const id = messageID.trim();
5925
+ if (!session || !id)
5926
+ return null;
5927
+ const { stdout } = await execFileAsync(awCommand, ["chat", "history", "--session-id", session, "--message-id", id, "--limit", "1", "--json"], { cwd: options.workdir, timeout: 15e3, maxBuffer: 1024 * 1024 });
5928
+ const payload = parseJSONOutput(stdout);
5929
+ return (payload.messages || []).find((msg) => msg.message_id === id) || null;
5930
+ }
5931
+ };
5932
+ }
5933
+ function parseJSONOutput(stdout) {
5934
+ const trimmed = stdout.trim();
5935
+ if (!trimmed)
5936
+ throw new Error("aw returned empty JSON output");
5937
+ const start = trimmed.indexOf("{");
5938
+ if (start < 0)
5939
+ throw new Error("aw JSON output did not contain an object");
5940
+ return JSON.parse(trimmed.slice(start));
5941
+ }
5942
+
5907
5943
  // ../channel-core/dist/channel.js
5908
5944
  import { dirname as dirname2, join as join2 } from "node:path";
5909
5945
  import { homedir } from "node:os";
@@ -6003,11 +6039,12 @@ function createChannelClient(config) {
6003
6039
  async function startChannelLoop(options) {
6004
6040
  const dispatched = /* @__PURE__ */ new Set();
6005
6041
  const deliveryStore = options.deliveryStore || await DeliveryStore.load(DEFAULT_DELIVERY_STORE_PATH);
6042
+ const localDecrypt = options.localDecrypt || (options.workdir ? createLocalAWDecryptProvider({ workdir: options.workdir, awCommand: options.awCommand }) : void 0);
6006
6043
  const log = options.log || (() => {
6007
6044
  });
6008
6045
  for await (const event of streamAgentEvents(options.client, options.signal)) {
6009
6046
  try {
6010
- await dispatchAgentEvent({ ...options, deliveryStore }, dispatched, event);
6047
+ await dispatchAgentEvent({ ...options, deliveryStore, localDecrypt }, dispatched, event);
6011
6048
  pruneDispatched(dispatched);
6012
6049
  } catch (err2) {
6013
6050
  log(`[aw-channel] dispatch error: ${err2}`);
@@ -6089,6 +6126,16 @@ async function dispatchMailEvent(options, dispatched, event) {
6089
6126
  continue;
6090
6127
  }
6091
6128
  const from = senderDisplayAddress(msg.from_alias, msg.from_address);
6129
+ const decrypt = await resolveMailForDelivery(options, msg);
6130
+ if (!decrypt.ok) {
6131
+ await options.onAwakening({
6132
+ kind: "mail",
6133
+ content: "",
6134
+ meta: encryptedDeliveryFailureMeta("mail", from, msg.message_id, conversationID, decrypt.error),
6135
+ deliveryIntent: "wake"
6136
+ });
6137
+ continue;
6138
+ }
6092
6139
  const trust = await normalizeMessageTrust(options, msg, msg.from_alias, msg.from_address, msg.to_did, msg.to_stable_id);
6093
6140
  msg.verification_status = trust.status;
6094
6141
  if (trust.stored)
@@ -6138,6 +6185,16 @@ async function dispatchChatEvent(options, dispatched, event) {
6138
6185
  continue;
6139
6186
  }
6140
6187
  const from = senderDisplayAddress(msg.from_agent, msg.from_address);
6188
+ const decrypt = await resolveChatForDelivery(options, event.session_id, msg);
6189
+ if (!decrypt.ok) {
6190
+ await options.onAwakening({
6191
+ kind: "chat",
6192
+ content: "",
6193
+ meta: encryptedDeliveryFailureMeta("chat", from, msg.message_id, conversationID, decrypt.error, event.session_id),
6194
+ deliveryIntent: event.sender_waiting ? "steer" : "wake"
6195
+ });
6196
+ continue;
6197
+ }
6141
6198
  const trust = await normalizeMessageTrust(options, msg, msg.from_agent, msg.from_address, msg.to_did, msg.to_stable_id);
6142
6199
  msg.verification_status = trust.status;
6143
6200
  if (trust.stored)
@@ -6177,6 +6234,58 @@ async function dispatchChatEvent(options, dispatched, event) {
6177
6234
  async function normalizeMessageTrust(options, msg, fromAlias, fromAddress, toDID, toStableID) {
6178
6235
  return options.trust.normalizeTrust(options.pinStore, msg.verification_status, senderTrustAddress(fromAlias, fromAddress), msg.from_did, msg.from_stable_id, toDID, toStableID, msg.rotation_announcement, msg.replacement_announcement, msg.signed_from || fromAddress || fromAlias || "");
6179
6236
  }
6237
+ async function resolveMailForDelivery(options, msg) {
6238
+ if (!isEncryptedMessage(msg))
6239
+ return { ok: true };
6240
+ if (!options.localDecrypt?.mailMessage) {
6241
+ return { ok: false, error: "local aw decrypt provider is not configured" };
6242
+ }
6243
+ try {
6244
+ const decrypted = await options.localDecrypt.mailMessage(msg.message_id);
6245
+ if (!decrypted || typeof decrypted.body !== "string") {
6246
+ return { ok: false, error: "local aw did not return decrypted mail body" };
6247
+ }
6248
+ Object.assign(msg, decrypted);
6249
+ return { ok: true };
6250
+ } catch (error) {
6251
+ return { ok: false, error: error instanceof Error ? error.message : String(error) };
6252
+ }
6253
+ }
6254
+ async function resolveChatForDelivery(options, sessionID, msg) {
6255
+ if (!isEncryptedMessage(msg))
6256
+ return { ok: true };
6257
+ if (!options.localDecrypt?.chatMessage) {
6258
+ return { ok: false, error: "local aw decrypt provider is not configured" };
6259
+ }
6260
+ try {
6261
+ const decrypted = await options.localDecrypt.chatMessage(sessionID, msg.message_id);
6262
+ if (!decrypted || typeof decrypted.body !== "string") {
6263
+ return { ok: false, error: "local aw did not return decrypted chat body" };
6264
+ }
6265
+ Object.assign(msg, decrypted);
6266
+ return { ok: true };
6267
+ } catch (error) {
6268
+ return { ok: false, error: error instanceof Error ? error.message : String(error) };
6269
+ }
6270
+ }
6271
+ function isEncryptedMessage(msg) {
6272
+ return msg.content_mode === "encrypted_v2" || msg.message_version === 2 || msg.encrypted_envelope !== void 0;
6273
+ }
6274
+ function encryptedDeliveryFailureMeta(type2, from, messageID, conversationID, error, sessionID) {
6275
+ const meta = {
6276
+ type: type2,
6277
+ from,
6278
+ message_id: messageID,
6279
+ encrypted: "true",
6280
+ decrypted: "false",
6281
+ decrypt_error: error
6282
+ };
6283
+ if (conversationID)
6284
+ meta.conversation_id = conversationID;
6285
+ if (sessionID)
6286
+ meta.session_id = sessionID;
6287
+ return meta;
6288
+ }
6180
6289
  function isTrustedVerificationStatus(status) {
6181
6290
  return status === "verified" || status === "verified_custodial";
6182
6291
  }
@@ -6486,6 +6595,7 @@ ${message}`),
6486
6595
  stableID: config.stableID
6487
6596
  },
6488
6597
  signal,
6598
+ workdir: ctx.cwd,
6489
6599
  onAwakening: (awakening) => sendAwakening(pi, awakening),
6490
6600
  log: (message) => {
6491
6601
  if (ctx.hasUI) ctx.ui.notify(message, "warning");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awebai/pi",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "Aweb for Pi: real-time channel awakenings, aw CLI onboarding, and aweb skills.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: aweb-bootstrap
3
- description: This skill should be used when helping a human create or join an aweb team from a template (aw team bootstrap), choosing a template and team source (hosted new team, BYOT, API key, invite, or current workspace forwarding), selecting work-directory vs work-repo-url, provisioning optional worktree agents, and validating/re-running bootstrap safely.
3
+ description: This skill should be used when helping a human create or join an aweb team from a template (aw team bootstrap), choosing a template and team source (hosted new team, BYOT, API key, invite, or current workspace forwarding), using the project-local agents/ layout or legacy work-directory/work-repo-url mode, provisioning optional worktree-bound agents, and validating/re-running bootstrap safely.
4
4
  allowed-tools: "Bash(aw *)"
5
5
  ---
6
6
 
@@ -20,27 +20,35 @@ Long-form reference: docs/team-bootstrap.md in the aweb repo.
20
20
 
21
21
  ## Mental model: what bootstrap is assembling
22
22
 
23
- `aw team bootstrap` combines four separate things that are easy to confuse:
23
+ `aw team bootstrap` combines five separate things that are easy to confuse:
24
24
 
25
25
  1) Template repo — the blueprint.
26
26
 
27
- - Contains `team.yaml`, role playbooks, shared instructions, and `agents/<responsibility>/AGENTS.md` files.
27
+ - Contains `team.yaml`, role playbooks, shared instructions, and `home/<responsibility>/AGENTS.md` files.
28
28
  - The template says what responsibilities should exist and which `role_name` each should use.
29
29
 
30
- 2) Work directory or work repo the thing agents work on.
30
+ 2) Generated project-local agents directorywhere humans start agents.
31
31
 
32
- - `--work-directory` points at an existing folder.
33
- - `--work-repo-url` clones a repo into `<template>/worktrees/<derived-name>/` and uses that clone as the work directory.
34
- - Each responsibility workspace gets this directory symlinked as `./work`.
32
+ - By default, run bootstrap from the root of the work repo.
33
+ - Bootstrap creates `agents/` in that repo. Every live agent home is under `agents/home/<responsibility>/`.
34
+ - The coordinator/global-style home normally has `work -> <repo-root>`.
35
+ - Worktree-bound homes still live under `agents/home/<responsibility>/`; their `work` symlink points at `agents/worktrees/<alias-or-responsibility>/`.
36
+ - Use `--agents-dir <name>` only when the repo already uses `agents/` for something else. If the target directory exists, bootstrap must fail before side effects.
35
37
 
36
- 3) Team source the authority/context the generated agents join.
38
+ 3) Legacy work directory or work repo compatibility mode.
39
+
40
+ - Passing `--work-directory` or `--work-repo-url` selects the old out-of-repo layout.
41
+ - Do not combine `--agents-dir` with either legacy work flag.
42
+ - Legacy mode is still supported for existing scripts/templates, but do not choose it for a new customer unless they explicitly need the old shape.
43
+
44
+ 4) Team source — the authority/context the generated agents join.
37
45
 
38
46
  - Hosted new team, existing hosted team via `AWEB_API_KEY`, explicit `--invite-token`, current workspace forwarding, or BYOT.
39
47
  - Exactly one explicit source is allowed. If no explicit source is set and cwd is already an aw workspace, bootstrap forwards that current team. If no current workspace exists and the run is interactive, bootstrap creates a hosted team. Non-interactive runs need an explicit source.
40
48
 
41
- 4) Generated workspaces — the identities that will act.
49
+ 5) Generated workspaces — the identities that will act.
42
50
 
43
- - Each `agents/<responsibility>/` directory becomes an aw workspace with its own identity and team certificate.
51
+ - Each `agents/home/<responsibility>/` directory becomes an aw workspace with its own identity and team certificate.
44
52
  - The **first generated plan** is the anchor: bootstrap connects it first, installs roles/instructions from that workspace's team context, then invites/connects the rest.
45
53
  - Do not assume a responsibility named `implementation` is special. The anchor is the first plan the CLI generated.
46
54
 
@@ -70,6 +78,9 @@ Do NOT bootstrap when:
70
78
 
71
79
  Canonical templates:
72
80
 
81
+ - awebai/aweb-team-coord-worktrees (3 agents)
82
+ Use when you want a coordinator plus isolated developer/reviewer git worktrees in the current repo.
83
+
73
84
  - awebai/aweb-team-dev-review (2 agents)
74
85
  Use when you want the smallest meaningful team: implementation + review.
75
86
 
@@ -80,7 +91,7 @@ Fork/edit vs use-as-is:
80
91
 
81
92
  - Use as-is to learn the flow or to run a standard team.
82
93
  - Clone or fork when you want to customize roles, responsibilities, or instructions before provisioning.
83
- - It is safe to edit the template checkout before applying it; `aw team bootstrap` reads `team.yaml`, `roles/`, `docs/`, and `agents/` from the local template directory at run time.
94
+ - It is safe to edit the template checkout before applying it; `aw team bootstrap` reads `team.yaml`, `roles/`, `docs/`, and `home/` from the local template directory at run time.
84
95
 
85
96
  ## Customizing a template before applying it
86
97
 
@@ -91,54 +102,87 @@ Typical safe flow:
91
102
  ```bash
92
103
  git clone https://github.com/awebai/aweb-team-dev-review.git my-team-template
93
104
  cd my-team-template
94
- # edit team.yaml, roles/*.md, docs/team.md, agents/<responsibility>/AGENTS.md
95
- aw team bootstrap . --dry-run --work-directory /path/to/work
96
- aw team bootstrap . --work-directory /path/to/work
105
+ # edit team.yaml, roles/*.md, docs/team.md, home/<responsibility>/AGENTS.md
106
+ cd /path/to/project-repo
107
+ aw team bootstrap /path/to/my-team-template --dry-run
108
+ aw team bootstrap /path/to/my-team-template --username alice
97
109
  ```
98
110
 
99
111
  What to edit:
100
112
 
101
113
  - `team.yaml` roles: add/remove role names and point each to a role file.
102
- - `team.yaml` agents: add/remove responsibility workspaces and set each `role_name`, `default_name`, and `default_alias`.
103
- - `team.yaml` worktrees: add/remove local git-worktree agents for code work.
114
+ - `team.yaml` agents: add/remove responsibility workspaces and set each `role_name`, `default_name`, `default_alias`, optional `home_template`, and optional `work`.
115
+ - Use `work: repo_root` for an agent whose `work` symlink points to the project repo root.
116
+ - Use `work: git_worktree` for an agent whose `work` symlink points to a generated git worktree under `agents/worktrees/`.
104
117
  - `roles/*.md`: change operational playbooks installed with `aw roles`.
105
118
  - `docs/team.md`: change shared team instructions installed after the anchor connects.
106
- - `agents/<responsibility>/AGENTS.md`: change per-workspace startup context.
119
+ - `home/<responsibility>/AGENTS.md`: change per-workspace startup context.
107
120
 
108
121
  Default agent names are accepted automatically. Only use `--ask-for-agent-names` when a human specifically wants an interactive rename prompt during bootstrap.
109
122
 
110
123
  ## Before running bootstrap (safety checks)
111
124
 
112
- 1) Run bootstrap from a directory that is NOT already inside a git repo/worktree.
125
+ 1) For the default layout, run bootstrap from the root of the project git repo.
113
126
 
114
- - If you are inside a git repo/worktree and you are using a remote template ref, bootstrap will refuse to clone by default.
115
- - Use `--template-cache-dir` as the explicit escape hatch when you must run from inside a repo.
127
+ - Bootstrap creates `agents/` there.
128
+ - If `agents/` exists, stop. Do not ask bootstrap to adopt, merge, or overwrite it.
129
+ - If the project already has a different `agents/` directory, ask the human for a different `--agents-dir <name>`.
116
130
 
117
- 2) Decide the “work” directory model (see next section). This affects whether agents share one checkout or get isolated worktrees.
131
+ 2) Decide the team source. This affects whether bootstrap creates a new hosted team, joins an API-key/invite team, forwards the current team, or uses BYOT.
118
132
 
119
- ## Exactly one of: work-directory OR work-repo-url (XOR)
133
+ 3) Use legacy work flags only for old out-of-repo bootstrap scripts.
120
134
 
121
- Bootstrap needs a directory to symlink into each agent workspace as ./work.
135
+ ## Default layout: project-local agents/
122
136
 
123
- You must provide exactly one of:
137
+ New bootstrap runs should normally use the default layout:
124
138
 
125
- A) --work-directory PATH
139
+ ```bash
140
+ cd /path/to/project-repo
141
+ aw team bootstrap https://github.com/awebai/aweb-team-coord-worktrees.git --username alice
142
+ ```
126
143
 
127
- - Use when you already have a local directory you want agents to use as work.
128
- - For code teams with worktree agents (team.yaml worktrees:), PATH must be a git repo.
144
+ Expected generated shape:
145
+
146
+ ```text
147
+ agents/
148
+ team.yaml
149
+ docs/
150
+ roles/
151
+ home/
152
+ coordinator/
153
+ .aw/
154
+ AGENTS.md
155
+ work -> ../../..
156
+ developer/
157
+ .aw/
158
+ AGENTS.md
159
+ work -> ../../worktrees/dev
160
+ reviewer/
161
+ .aw/
162
+ AGENTS.md
163
+ work -> ../../worktrees/review
164
+ worktrees/
165
+ dev/
166
+ review/
167
+ ```
168
+
169
+ The repo root itself is not an aw workspace. Start Codex, Claude Code, or Pi from an agent home, for example:
129
170
 
130
- B) --work-repo-url VALUE
171
+ ```bash
172
+ cd agents/home/coordinator
173
+ codex
174
+ ```
131
175
 
132
- - Use when you want bootstrap to clone a repo for you.
133
- - VALUE can be a URL or a local path; bootstrap runs “git clone VALUE” into:
176
+ Bootstrap writes scoped `.gitignore` entries for `agents/home/*/.aw/` and `agents/worktrees/`. It must not ignore the whole `agents/` directory.
134
177
 
135
- <template-checkout>/worktrees/<derived-name>/
178
+ ## Legacy mode: work-directory OR work-repo-url (XOR)
136
179
 
137
- where <derived-name> matches git’s default directory naming (basename, .git stripped).
180
+ Use legacy mode only for existing scripts/templates that expect generated homes outside the work repo.
138
181
 
139
- - That clone destination is then used as the effective work directory (symlinked as ./work in each agent workspace).
182
+ - `--work-directory PATH`: use an existing local directory as each responsibility workspace's `./work`.
183
+ - `--work-repo-url VALUE`: clone a repo into `<template-checkout>/worktrees/<derived-name>/` and use that clone as `./work`.
140
184
 
141
- If both flags are set, treat it as a user error and stop.
185
+ If both flags are set, treat it as a user error and stop. If `--agents-dir` is combined with either legacy flag, treat it as a user error and stop.
142
186
 
143
187
  ## Team source policy
144
188
 
@@ -199,16 +243,17 @@ Policy guidance:
199
243
  - Prefer BYOT when you need local control over the team namespace/domain and routing.
200
244
  - Use `--dry-run` for planning only. It prints the resolved plan (template ref, work directory, team source, generated workspaces) without writing identities, files, or server state. Do not pair it with side-effecting flags expecting partial provisioning.
201
245
 
202
- ## Worktree agents (team.yaml worktrees:)
246
+ ## Worktree-bound agents (`work: git_worktree`)
203
247
 
204
- Worktree agents are an OPTIONAL second layer for codebases where multiple agents will edit in parallel.
248
+ Worktree-bound agents are for codebases where multiple agents will edit in parallel.
205
249
 
206
- - Responsibility workspaces live under agents/<responsibility>/.
207
- - Worktree agents live under worktrees/ and each has its own git worktree checkout and its own .aw/ identity state.
250
+ - Every live home stays under `agents/home/<responsibility>/`.
251
+ - A `work: git_worktree` agent gets a git checkout under `agents/worktrees/<alias-or-responsibility>/`.
252
+ - Its home has `work -> ../../worktrees/<alias-or-responsibility>`.
208
253
 
209
- Turn worktree agents on when:
254
+ Use `work: git_worktree` when:
210
255
 
211
- - The work directory is a git repo.
256
+ - The project directory is a git repo.
212
257
  - Multiple agents will change files in parallel.
213
258
  - You want each agent’s edits isolated until you merge.
214
259
 
@@ -219,11 +264,11 @@ Leave it off when:
219
264
 
220
265
  Operational note:
221
266
 
222
- - Worktree agents are local-only identities by design; they are for parallel local work, not for global addressability.
267
+ - Worktree-bound agents are local identities by default; they are for parallel local work, not for global addressability.
223
268
 
224
269
  ## After bootstrap: validate that the team is actually usable
225
270
 
226
- For each agent directory under agents/<responsibility>/:
271
+ For each agent directory under `agents/home/<responsibility>/`:
227
272
 
228
273
  - Run `aw workspace status` to confirm:
229
274
  - the workspace is initialized
@@ -242,6 +287,7 @@ When iterating on templates or recovering from partial setup:
242
287
  - Use `--refresh-template` only when you intend to re-clone over a previous template checkout.
243
288
  - Treat identity/certificate state under .aw/ as the source of truth; do not delete it casually.
244
289
  - If you need to create a fresh workspace, do it in a new directory rather than mutating an existing identity in place.
290
+ - If `agents/` already exists, do not retry over it. Pick a different `--agents-dir` or remove the existing directory only if the human confirms it is disposable.
245
291
 
246
292
  If bootstrap fails mid-way:
247
293
 
@@ -6,8 +6,9 @@ It is intentionally narrower than docs/team-bootstrap.md: it focuses on common d
6
6
 
7
7
  ## Quick mental model
8
8
 
9
- - Template repo = blueprint for roles, instructions, and responsibility directories.
10
- - Work directory/repo = the project/content agents see as `./work`.
9
+ - Template repo = blueprint for roles, instructions, and agent home templates.
10
+ - Default generated layout = project-local `agents/` directory containing `home/`, `worktrees/`, `roles/`, `docs/`, and `team.yaml`.
11
+ - Work target = what each agent's `work` symlink points at: the repo root (`work: repo_root`) or a generated git worktree (`work: git_worktree`).
11
12
  - Team source = the authority the generated agents join.
12
13
  - First generated workspace = bootstrap anchor. It connects first; roles/instructions install through it; all other generated agents join through invites from that established team context.
13
14
  - BYOT means bring your own team, including your own namespace/domain and controller key. Do not present a separate domain-only bootstrap mode.
@@ -25,27 +26,28 @@ Goal: create a new aweb.ai team and provision agent workspaces from a template.
25
26
 
26
27
  Checklist:
27
28
 
28
- - Run from a directory that is not inside an existing git repo/worktree.
29
+ - Run from the root of the project git repo.
30
+ - Confirm the target agents directory does not already exist. Default: `agents/`.
29
31
  - Pick a template:
32
+ - awebai/aweb-team-coord-worktrees for coordinator + developer/reviewer worktrees.
30
33
  - awebai/aweb-team-dev-review for a minimal 2-agent setup.
31
34
  - awebai/aweb-team-company-surfaces for a 6-agent cross-functional setup.
32
35
 
33
- Example (using an existing local work directory):
36
+ Example:
34
37
 
35
- aw team bootstrap https://github.com/awebai/aweb-team-dev-review.git --username alice --work-directory /path/to/work
38
+ cd /path/to/project-repo
39
+ aw team bootstrap https://github.com/awebai/aweb-team-coord-worktrees.git --username alice
36
40
 
37
- Example (clone the work repo into the template checkout):
41
+ Example with a non-default agents directory:
38
42
 
39
- aw team bootstrap https://github.com/awebai/aweb-team-dev-review.git --username alice --work-repo-url https://github.com/ORG/REPO.git
43
+ cd /path/to/project-repo
44
+ aw team bootstrap https://github.com/awebai/aweb-team-coord-worktrees.git --username alice --agents-dir aweb-agents
40
45
 
41
46
  Notes:
42
47
 
43
- - work-directory and work-repo-url are XOR: set exactly one.
44
- - When work-repo-url is used, bootstrap clones into:
45
-
46
- <template-checkout>/worktrees/<derived-name>/
47
-
48
- where derived-name is the git-style repo directory name (basename with .git stripped).
48
+ - Bootstrap creates `agents/home/<agent>/` for every live agent home.
49
+ - Worktree-bound agents get checkouts under `agents/worktrees/<alias-or-agent>/`.
50
+ - The repo root is not an aw workspace; humans should start Codex/Claude/Pi from `agents/home/<agent>/`.
49
51
 
50
52
  ## Scenario: customize the template before applying it
51
53
 
@@ -54,17 +56,18 @@ Goal: change roles, agent responsibilities, names, aliases, or instructions befo
54
56
  Checklist:
55
57
 
56
58
  - Clone or fork the template first.
57
- - Edit `team.yaml`, `roles/*.md`, `docs/team.md`, and `agents/<responsibility>/AGENTS.md` as needed.
58
- - Run `aw team bootstrap . --dry-run ...` from the template checkout to validate.
59
- - Bootstrap the local directory only after the plan looks right.
59
+ - Edit `team.yaml`, `roles/*.md`, `docs/team.md`, and `home/<responsibility>/AGENTS.md` as needed.
60
+ - Run `aw team bootstrap /path/to/template --dry-run` from the project repo root to validate.
61
+ - Bootstrap the local template directory only after the plan looks right.
60
62
 
61
63
  Example:
62
64
 
63
65
  git clone https://github.com/awebai/aweb-team-dev-review.git my-team-template
64
66
  cd my-team-template
65
- # edit team.yaml / roles / docs / agents
66
- aw team bootstrap . --dry-run --work-directory /path/to/work
67
- aw team bootstrap . --username alice --work-directory /path/to/work
67
+ # edit team.yaml / roles / docs / home
68
+ cd /path/to/project-repo
69
+ aw team bootstrap /path/to/my-team-template --dry-run
70
+ aw team bootstrap /path/to/my-team-template --username alice
68
71
 
69
72
  ## Scenario: BYOT (bring your own team)
70
73
 
@@ -80,8 +83,7 @@ Example shape (values are placeholders):
80
83
 
81
84
  aw team bootstrap https://github.com/awebai/aweb-team-dev-review.git \
82
85
  --namespace example.com \
83
- --team dev \
84
- --work-directory /path/to/work
86
+ --team dev
85
87
 
86
88
  If you are also self-hosting the coordination stack, add:
87
89
 
@@ -101,7 +103,7 @@ Checklist:
101
103
  Example:
102
104
 
103
105
  AWEB_API_KEY=aw_sk_... \
104
- aw team bootstrap /path/to/template --work-directory /path/to/work
106
+ aw team bootstrap /path/to/template
105
107
 
106
108
  ## Scenario: existing team via invite token
107
109
 
@@ -110,8 +112,7 @@ Goal: accept an invite into the first generated workspace and use it as the anch
110
112
  Example:
111
113
 
112
114
  aw team bootstrap /path/to/template \
113
- --invite-token <token> \
114
- --work-directory /path/to/work
115
+ --invite-token <token>
115
116
 
116
117
  ## Scenario: current workspace forwarding
117
118
 
@@ -129,22 +130,32 @@ Goal: validate the plan and see generated workspace commands without changing fi
129
130
 
130
131
  Example:
131
132
 
132
- aw team bootstrap /path/to/template --dry-run --work-directory /path/to/work
133
+ aw team bootstrap /path/to/template --dry-run
134
+
135
+ ## Legacy mode: old out-of-repo bootstrap
136
+
137
+ Use legacy mode only for existing scripts/templates that still expect the old layout.
138
+
139
+ - `--work-directory <path>` selects legacy work-directory mode.
140
+ - `--work-repo-url <url-or-local-path>` selects legacy clone-then-bootstrap mode.
141
+ - The two flags are XOR.
142
+ - Do not combine `--agents-dir` with either legacy work flag.
133
143
 
134
- ## Worktree agents: when to enable and what to expect
144
+ ## Worktree-bound agents: when to enable and what to expect
135
145
 
136
- Use worktree agents when multiple agents will edit code in parallel.
146
+ Use `work: git_worktree` when multiple agents will edit code in parallel.
137
147
 
138
148
  Requirements:
139
149
 
140
- - The work directory must be a git repo.
141
- - The template must declare a worktrees: block in team.yaml.
150
+ - The project directory must be a git repo.
151
+ - The template declares `work: git_worktree` for the relevant agent in `team.yaml`.
142
152
 
143
153
  What bootstrap does:
144
154
 
145
- - It creates template worktrees/ (if missing) and git-excludes it locally.
146
- - It creates one git worktree per entry.
147
- - Each worktree agent gets its own .aw/ state and local-scope identity.
155
+ - It creates `agents/worktrees/` and writes scoped `.gitignore` entries.
156
+ - It creates one git worktree per `work: git_worktree` agent.
157
+ - The live agent home remains under `agents/home/<responsibility>/`.
158
+ - Each worktree-bound agent gets its own `.aw/` state and local-scope identity.
148
159
 
149
160
  Common pitfall:
150
161
 
@@ -152,7 +163,7 @@ Common pitfall:
152
163
 
153
164
  ## Quick validation after bootstrap
154
165
 
155
- In each generated agent directory (agents/<responsibility>/):
166
+ In each generated agent directory (`agents/home/<responsibility>/`):
156
167
 
157
168
  - aw workspace status
158
169
  - aw whoami
@@ -67,7 +67,7 @@ The normative E2E contract is `docs/e2e-messaging-contract.md`. Do not invent pr
67
67
 
68
68
  For local E2E messaging, the self-custodial client needs both identity signing material and local encryption private keys. Back up the active encryption private key and archived encryption private keys with the same seriousness as `.aw/signing.key`: losing archived encryption keys makes historical encrypted messages unrecoverable. AC/aweb cannot recover or decrypt old encrypted messages for support.
69
69
 
70
- An identity must publish an identity-signed encryption-key assertion before it can receive E2E messages. Missing, stale, unsigned, or mismatched encryption-key discovery fails closed; do not retry as plaintext unless the human explicitly chooses the separately named legacy plaintext mode from the final CLI. Service signatures may assert route support, but not recipient encryption-key authority. Local identities omit absent `stable_id`/address fields instead of sending empty strings. In non-interactive runs, stop, report the exact `aw doctor` / command error, and ask the human or coordinator to run the approved key setup, backup, or rotation flow.
70
+ An identity must publish an identity-signed encryption-key assertion before it can receive E2E messages. New self-custodial identity and team-install paths create local encryption key material automatically, including `aw id create`, `aw init`, `aw service init`, `aw id team accept-invite`, `aw id team fetch-cert`, and bootstrap/add-worktree flows. Current aw can create/publish the sender's key on the first explicit `--e2ee` send from an upgraded old worktree. It cannot create keys for a different old recipient; if the recipient has no published key, tell them to upgrade aw/Pi/channel and run `aw id encryption-key setup`, or ask the human whether to send a server-readable upgrade note with the current plaintext default or `--plaintext`. Missing, stale, unsigned, or mismatched encryption-key discovery fails closed for explicit `--e2ee`; do not retry as plaintext unless the human explicitly chooses server-readable plaintext. Service signatures may assert route support, but not recipient encryption-key authority. Local identities omit absent `stable_id`/address fields instead of sending empty strings. In non-interactive runs, stop, report the exact `aw doctor` / command error, and ask the human or coordinator to run the approved key setup, backup, or rotation flow.
71
71
 
72
72
  Use the CLI keyring commands for self-custodial E2E readiness:
73
73
 
@@ -79,7 +79,7 @@ aw id encryption-key show # inspect local keyring state
79
79
 
80
80
  `setup` stores the private key locally before publishing the public assertion. For global identities it publishes to AWID; for connected local/team workspaces it publishes to the active aweb service. `rotate` must not delete old private keys. After either command, remind the human to back up `.aw/encryption-keys/`.
81
81
 
82
- Hosted custodial MCP, dashboard-side send/read, and other server-side tools are **server-readable hosted messaging**, not E2E, because plaintext or decryption capability enters AC/aweb. Do not tell users that hosted custodial/server-side messaging is end-to-end encrypted unless a future design keeps plaintext and decryption fully outside AC.
82
+ Hosted custodial MCP, dashboard-side send/read, and other server-side tools are **server-readable hosted messaging**, not E2E, because plaintext or decryption capability enters AC/aweb. Do not use the end-to-end label for hosted custodial/server-side messaging unless a future design keeps plaintext and decryption fully outside AC.
83
83
 
84
84
  AWID controller keys are separate from worktree identity keys. Namespace and team controller keys live under `~/.awid/`; they are authority keys, not app config. Keep that directory safe and backed up. Worktree identity keys (`.aw/signing.key`) remain with the workspace they act from.
85
85
 
@@ -161,7 +161,7 @@ Interpret failures by what's missing (file references assume a self-custodial CL
161
161
 
162
162
  - **No `.aw/` in this directory** — there is no workspace here at all. Run `aw init` or move to a directory that has been initialized.
163
163
  - **`.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.
164
- - **E2E encryption-key check fails** — distinguish the cases the CLI reports: missing local encryption private key, missing published encryption-key assertion, stale/mismatched assertion, or missing archived key for an older message. Do not advise plaintext fallback. Capture the exact error, run `aw doctor` when available, and ask the human to restore keys from backup or run `aw id encryption-key setup` / `aw id encryption-key rotate` as appropriate.
164
+ - **E2E encryption-key check fails** — distinguish the cases the CLI reports: missing local encryption private key, missing published encryption-key assertion, stale/mismatched assertion, or missing archived key for an older message. Do not advise plaintext fallback. Capture the exact error, run `aw doctor` when available, and ask the human to restore keys from backup or run `aw id encryption-key setup` / `aw id encryption-key rotate` as appropriate. Use `--plaintext` only when the human explicitly chooses server-readable plaintext.
165
165
  - **`.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`.
166
166
  - **No global identity / no `did:aw` registered** — only a local workspace identity exists. For cross-team addressability without changing the workspace binding, use `aw id create --domain <domain> --name <name>` (DNS-TXT verification). Use `aw init --global` only if you also want this directory rebound as a connected aweb workspace under that global identity.
167
167
  - **Already ran `aw init --byod --global` expecting offline BYOT prep** — that command bootstrapped and connected this directory to the `default:<domain>` team on app.aweb.ai (the team created during BYOD onboarding), leaving `.aw/{identity.yaml,signing.key,teams.yaml,workspace.yaml,team-certs/}` populated. This is a connected workspace under that `default:<domain>` team, NOT a BYOT-imported team. To recover, pick one:
@@ -10,9 +10,11 @@ This skill is the playbook for aweb channel awakenings. When you receive an inje
10
10
 
11
11
  It also covers explicit user requests to send mail or chat through aweb.
12
12
 
13
- E2E messaging boundary: for encrypted v2 messages, AC/aweb servers route ciphertext and local clients decrypt before showing or injecting plaintext. Hosted custodial MCP, dashboard-side send/read, and server-side tools are **server-readable hosted messaging**, not E2E. Do not describe hosted custodial/server-side messaging as end-to-end encrypted.
13
+ E2E messaging boundary: for encrypted v2 messages, AC/aweb servers route ciphertext and local clients decrypt before showing or injecting plaintext. Hosted custodial MCP, dashboard-side send/read, and server-side tools are **server-readable hosted messaging**, not E2E. Do not use the end-to-end label for hosted custodial/server-side messaging.
14
14
 
15
- Legacy plaintext boundary: existing plaintext mail/chat remains legacy/server-readable while retained and must not be described as retroactively E2E. If an intended E2E send fails because keys, capability, route support, or version support is missing/stale/mismatched, stop and report the exact failure. Do not resend as plaintext unless the human explicitly chooses the approved legacy plaintext command/flag.
15
+ Interim plaintext boundary: in the current aw CLI release, mail and chat are server-readable plaintext by default. Do not describe default CLI mail/chat as E2E. Pass `--e2ee` only when the human explicitly wants encrypted send; if that encrypted send fails because keys, capability, route support, or version support is missing/stale/mismatched, stop and report the exact failure. Do not silently retry as plaintext.
16
+
17
+ Mixed-version boundary: old pre-E2E aw/channel/Pi clients may not have published recipient encryption keys yet. A current aw CLI can create/publish the sender's local encryption key for explicit `--e2ee` sends, but it cannot create keys for another recipient. If the recipient lacks a key, report that they need to upgrade aw/Pi/channel and publish a key. Plain default sends and `--plaintext` are server-readable.
16
18
 
17
19
  If the event says to use the aw CLI and the response is not obvious, continue with this skill. For broader work coordination, load `aweb-coordination`. For recipient addressability, inbound-mode policy, team membership, or multi-team identity questions, load `aweb-team-membership`.
18
20
 
@@ -77,15 +79,15 @@ aw chat extend-wait <from> "working on it, 2 minutes"
77
79
 
78
80
  Before replying to a confusing chat, inspect pending/open/history state. Do not use chat for broad FYI updates. Send mail instead.
79
81
 
80
- Encrypted chat is explicit. Use `--e2ee` only when the human or policy asks for E2E chat and every participant has identity-authorized encryption capability:
82
+ Mail and chat are server-readable plaintext by default in the current aw CLI release. Add `--e2ee` only when the human explicitly wants an encrypted send; it fails closed if keys, capability, route support, or version support are missing. `--plaintext` is an explicit clarifier for the current default.
81
83
 
82
84
  ```bash
83
- aw chat send-and-wait <alias-or-address> "..." --start-conversation --e2ee
84
- aw chat send-and-leave <alias-or-address> "..." --e2ee
85
- aw chat extend-wait <from> "working on it" --e2ee
85
+ aw chat send-and-wait <alias-or-address> "..." --start-conversation
86
+ aw chat send-and-leave <alias-or-address> "..."
87
+ aw chat extend-wait <from> "working on it"
86
88
  ```
87
89
 
88
- Read paths such as `aw chat pending`, `aw chat history`, and channel listen/decrypt paths show plaintext only after local decryption. If `--e2ee` fails because a key, capability, route, or version is missing or stale, stop and report the exact error; do not resend as plaintext unless the human explicitly chooses the approved legacy plaintext path.
90
+ Encrypted read paths such as `aw chat pending`, `aw chat history`, and channel listen/decrypt paths show plaintext only after local decryption. If an explicit `--e2ee` send fails because a key, capability, route, or version is missing or stale, stop and report the exact error; do not resend as plaintext unless the human explicitly chooses server-readable plaintext.
89
91
 
90
92
  ## Harness surfaces
91
93
 
@@ -109,7 +111,7 @@ Harness support differs:
109
111
 
110
112
  The channel is inbound only. Use `aw mail` or `aw chat` to respond.
111
113
 
112
- For E2E messages, channel/Pi/`aw run` may show plaintext only after local decryption in the user's workspace or client process. Server notifications and SSE payloads should be metadata-only for encrypted content. Recipient E2E capability and encryption keys must be identity-authorized; a service signature can assert route support only. If an event or tool error says an encryption key/capability is missing, stale, or mismatched, fail closed and report the error. Do not silently resend as plaintext.
114
+ For E2E messages, channel/Pi/`aw run` may show plaintext only after local decryption in the user's workspace or client process. Server notifications and SSE payloads should be metadata-only for encrypted content. Recipient E2E capability and encryption keys must be identity-authorized; a service signature can assert route support only. If an event or tool error says an encryption key/capability is missing, stale, or mismatched, fail closed and report the error. Do not silently resend as plaintext. If the local channel/Pi process was upgraded from a pre-E2E version, run `aw id encryption-key setup` in the workspace before expecting it to receive encrypted messages.
113
115
 
114
116
  ## Control and work awakenings
115
117