@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: 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),
|
|
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
|
|
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 `
|
|
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)
|
|
30
|
+
2) Generated project-local agents directory — where humans start agents.
|
|
31
31
|
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
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)
|
|
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
|
-
|
|
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 `
|
|
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,
|
|
95
|
-
|
|
96
|
-
aw team bootstrap
|
|
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 `
|
|
103
|
-
- `
|
|
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
|
-
- `
|
|
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)
|
|
125
|
+
1) For the default layout, run bootstrap from the root of the project git repo.
|
|
113
126
|
|
|
114
|
-
-
|
|
115
|
-
-
|
|
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
|
|
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
|
-
|
|
133
|
+
3) Use legacy work flags only for old out-of-repo bootstrap scripts.
|
|
120
134
|
|
|
121
|
-
|
|
135
|
+
## Default layout: project-local agents/
|
|
122
136
|
|
|
123
|
-
|
|
137
|
+
New bootstrap runs should normally use the default layout:
|
|
124
138
|
|
|
125
|
-
|
|
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
|
-
|
|
128
|
-
|
|
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
|
-
|
|
171
|
+
```bash
|
|
172
|
+
cd agents/home/coordinator
|
|
173
|
+
codex
|
|
174
|
+
```
|
|
131
175
|
|
|
132
|
-
|
|
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
|
-
|
|
178
|
+
## Legacy mode: work-directory OR work-repo-url (XOR)
|
|
136
179
|
|
|
137
|
-
|
|
180
|
+
Use legacy mode only for existing scripts/templates that expect generated homes outside the work repo.
|
|
138
181
|
|
|
139
|
-
-
|
|
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 (
|
|
246
|
+
## Worktree-bound agents (`work: git_worktree`)
|
|
203
247
|
|
|
204
|
-
Worktree agents are
|
|
248
|
+
Worktree-bound agents are for codebases where multiple agents will edit in parallel.
|
|
205
249
|
|
|
206
|
-
-
|
|
207
|
-
-
|
|
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
|
-
|
|
254
|
+
Use `work: git_worktree` when:
|
|
210
255
|
|
|
211
|
-
- The
|
|
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
|
|
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
|
|
10
|
-
-
|
|
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
|
|
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
|
|
36
|
+
Example:
|
|
34
37
|
|
|
35
|
-
|
|
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
|
|
41
|
+
Example with a non-default agents directory:
|
|
38
42
|
|
|
39
|
-
|
|
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
|
-
-
|
|
44
|
-
-
|
|
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 `
|
|
58
|
-
- Run `aw team bootstrap
|
|
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 /
|
|
66
|
-
|
|
67
|
-
aw team bootstrap
|
|
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
|
|
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
|
|
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
|
|
146
|
+
Use `work: git_worktree` when multiple agents will edit code in parallel.
|
|
137
147
|
|
|
138
148
|
Requirements:
|
|
139
149
|
|
|
140
|
-
- The
|
|
141
|
-
- The template
|
|
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
|
|
146
|
-
- It creates one git worktree per
|
|
147
|
-
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
84
|
-
aw chat send-and-leave <alias-or-address> "..."
|
|
85
|
-
aw chat extend-wait <from> "working on it"
|
|
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
|
-
|
|
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
|
|