






















@@ -0,0 +1,257 @@
1+# Crestodian ring-zero setup
2+3+```yaml qa-scenario
4+id: crestodian-ring-zero-setup
5+title: Crestodian ring-zero setup
6+surface: config
7+coverage:
8+primary:
9+ - config.crestodian-setup
10+secondary:
11+ - channels.discord-config
12+ - agents.create
13+objective: Verify Crestodian can bootstrap a fresh OpenClaw config, set the default model, create an agent, configure Discord through a SecretRef, validate config, and leave an audit trail.
14+successCriteria:
15+ - Crestodian reports missing config in an empty state dir.
16+ - Crestodian setup writes a workspace and default model.
17+ - Crestodian creates a non-main agent with its own workspace and model.
18+ - Crestodian enables the Discord plugin before writing Discord channel config.
19+ - Crestodian configures Discord through an env SecretRef without persisting the raw token.
20+ - Config validation passes and audit entries exist for every applied write.
21+docsRefs:
22+ - docs/cli/crestodian.md
23+ - docs/channels/discord.md
24+ - docs/help/testing.md
25+codeRefs:
26+ - src/crestodian/operations.ts
27+ - scripts/e2e/crestodian-first-run-docker-client.ts
28+ - extensions/qa-lab/src/suite-runtime-agent-process.ts
29+execution:
30+kind: flow
31+summary: Drive the public Crestodian CLI in an isolated fresh state dir and verify setup/model/agent/Discord/audit results.
32+config:
33+stateDirName: crestodian-ring-zero-state
34+defaultWorkspaceName: crestodian-main-workspace
35+agentWorkspaceName: crestodian-reef-workspace
36+agentId: reef
37+model: openai/gpt-5.2
38+discordEnv: DISCORD_BOT_TOKEN
39+discordToken: openclaw-crestodian-qa-discord-token
40+```
41+42+```yaml qa-flow
43+steps:
44+ - name: bootstraps config through Crestodian CLI
45+actions:
46+ - set: stateDir
47+value:
48+expr: "path.join(env.gateway.tempRoot, config.stateDirName)"
49+ - set: configPath
50+value:
51+expr: "path.join(stateDir, 'openclaw.json')"
52+ - set: defaultWorkspace
53+value:
54+expr: "path.join(env.gateway.tempRoot, config.defaultWorkspaceName)"
55+ - set: agentWorkspace
56+value:
57+expr: "path.join(env.gateway.tempRoot, config.agentWorkspaceName)"
58+ - set: crestodianEnv
59+value:
60+expr: "({ OPENCLAW_STATE_DIR: stateDir, OPENCLAW_CONFIG_PATH: configPath, OPENCLAW_BUNDLED_PLUGINS_DIR: path.join(env.repoRoot, 'dist', 'extensions'), [config.discordEnv]: config.discordToken })"
61+ - call: fs.rm
62+args:
63+ - ref: stateDir
64+ - recursive: true
65+force: true
66+ - call: fs.mkdir
67+args:
68+ - ref: stateDir
69+ - recursive: true
70+ - call: runQaCli
71+saveAs: overviewOutput
72+args:
73+ - ref: env
74+ - - crestodian
75+ - -m
76+ - overview
77+ - timeoutMs: 60000
78+env:
79+ref: crestodianEnv
80+ - assert:
81+expr: "String(overviewOutput).includes('Config: missing')"
82+message:
83+expr: "`fresh Crestodian overview did not report missing config: ${overviewOutput}`"
84+ - assert:
85+expr: 'String(overviewOutput).includes(''Next: run "setup" to create a starter config'')'
86+message:
87+expr: "`fresh Crestodian overview did not recommend setup: ${overviewOutput}`"
88+ - call: runQaCli
89+saveAs: setupOutput
90+args:
91+ - ref: env
92+ - - crestodian
93+ - --yes
94+ - -m
95+ - expr: "`setup workspace ${defaultWorkspace} model ${config.model}`"
96+ - timeoutMs: 60000
97+env:
98+ref: crestodianEnv
99+ - assert:
100+expr: "String(setupOutput).includes('[crestodian] done: crestodian.setup')"
101+message:
102+expr: "`Crestodian setup did not apply: ${setupOutput}`"
103+ - call: runQaCli
104+saveAs: modelOutput
105+args:
106+ - ref: env
107+ - - crestodian
108+ - --yes
109+ - -m
110+ - expr: "`set default model ${config.model}`"
111+ - timeoutMs: 60000
112+env:
113+ref: crestodianEnv
114+ - assert:
115+expr: "String(modelOutput).includes('[crestodian] done: config.setDefaultModel')"
116+message:
117+expr: "`Crestodian model update did not apply: ${modelOutput}`"
118+ - call: runQaCli
119+saveAs: agentOutput
120+args:
121+ - ref: env
122+ - - crestodian
123+ - --yes
124+ - -m
125+ - expr: "`create agent ${config.agentId} workspace ${agentWorkspace} model ${config.model}`"
126+ - timeoutMs: 60000
127+env:
128+ref: crestodianEnv
129+ - assert:
130+expr: "String(agentOutput).includes('[crestodian] done: agents.create')"
131+message:
132+expr: "`Crestodian agent creation did not apply: ${agentOutput}`"
133+ - call: runQaCli
134+saveAs: discordPluginAllowOutput
135+args:
136+ - ref: env
137+ - - crestodian
138+ - --yes
139+ - -m
140+ - config set plugins.allow ["discord"]
141+ - timeoutMs: 60000
142+env:
143+ref: crestodianEnv
144+ - assert:
145+expr: "String(discordPluginAllowOutput).includes('[crestodian] done: config.set')"
146+message:
147+expr: "`Crestodian Discord plugin allowlist did not apply: ${discordPluginAllowOutput}`"
148+ - call: runQaCli
149+saveAs: discordPluginEntryOutput
150+args:
151+ - ref: env
152+ - - crestodian
153+ - --yes
154+ - -m
155+ - config set plugins.entries.discord.enabled true
156+ - timeoutMs: 60000
157+env:
158+ref: crestodianEnv
159+ - assert:
160+expr: "String(discordPluginEntryOutput).includes('[crestodian] done: config.set')"
161+message:
162+expr: "`Crestodian Discord plugin entry did not apply: ${discordPluginEntryOutput}`"
163+ - call: runQaCli
164+saveAs: discordTokenOutput
165+args:
166+ - ref: env
167+ - - crestodian
168+ - --yes
169+ - -m
170+ - expr: "`config set-ref channels.discord.token env ${config.discordEnv}`"
171+ - timeoutMs: 60000
172+env:
173+ref: crestodianEnv
174+ - assert:
175+expr: "String(discordTokenOutput).includes('[crestodian] done: config.setRef')"
176+message:
177+expr: "`Crestodian Discord SecretRef did not apply: ${discordTokenOutput}`"
178+ - call: runQaCli
179+saveAs: discordEnabledOutput
180+args:
181+ - ref: env
182+ - - crestodian
183+ - --yes
184+ - -m
185+ - config set channels.discord.enabled true
186+ - timeoutMs: 60000
187+env:
188+ref: crestodianEnv
189+ - assert:
190+expr: "String(discordEnabledOutput).includes('[crestodian] done: config.set')"
191+message:
192+expr: "`Crestodian Discord enable did not apply: ${discordEnabledOutput}`"
193+ - call: runQaCli
194+saveAs: validationOutput
195+args:
196+ - ref: env
197+ - - crestodian
198+ - -m
199+ - validate config
200+ - timeoutMs: 60000
201+env:
202+ref: crestodianEnv
203+ - assert:
204+expr: "String(validationOutput).includes('Config valid:')"
205+message:
206+expr: "`Crestodian config validation did not pass: ${validationOutput}`"
207+ - set: writtenConfig
208+value:
209+expr: "JSON.parse(await fs.readFile(configPath, 'utf8'))"
210+ - set: agent
211+value:
212+expr: "writtenConfig.agents?.list?.find((candidate) => candidate.id === config.agentId)"
213+ - assert:
214+expr: "writtenConfig.agents?.defaults?.workspace === defaultWorkspace"
215+message:
216+expr: "`default workspace mismatch: ${JSON.stringify(writtenConfig.agents?.defaults)}`"
217+ - assert:
218+expr: "writtenConfig.agents?.defaults?.model?.primary === config.model"
219+message:
220+expr: "`default model mismatch: ${JSON.stringify(writtenConfig.agents?.defaults?.model)}`"
221+ - assert:
222+expr: "agent?.workspace === agentWorkspace && agent?.model === config.model"
223+message:
224+expr: "`agent config mismatch: ${JSON.stringify(agent)}`"
225+ - assert:
226+expr: "writtenConfig.plugins?.allow?.includes('discord') && writtenConfig.plugins?.entries?.discord?.enabled === true"
227+message:
228+expr: "`Discord plugin was not enabled: ${JSON.stringify(writtenConfig.plugins)}`"
229+ - assert:
230+expr: "writtenConfig.channels?.discord?.enabled === true"
231+message:
232+expr: "`Discord was not enabled: ${JSON.stringify(writtenConfig.channels?.discord)}`"
233+ - assert:
234+expr: "writtenConfig.channels?.discord?.token?.source === 'env' && writtenConfig.channels?.discord?.token?.id === config.discordEnv"
235+message:
236+expr: "`Discord token was not an env SecretRef: ${JSON.stringify(writtenConfig.channels?.discord?.token)}`"
237+ - assert:
238+expr: "!JSON.stringify(writtenConfig.channels?.discord ?? {}).includes(config.discordToken)"
239+message: Crestodian persisted the raw Discord token.
240+ - set: auditText
241+value:
242+expr: "await fs.readFile(path.join(stateDir, 'audit', 'crestodian.jsonl'), 'utf8')"
243+ - forEach:
244+items:
245+ - crestodian.setup
246+ - config.setDefaultModel
247+ - agents.create
248+ - config.setRef
249+ - config.set
250+item: operation
251+actions:
252+ - assert:
253+expr: 'auditText.includes(`"operation":"${operation}"`)'
254+message:
255+expr: "`missing audit entry for ${operation}: ${auditText}`"
256+detailsExpr: "`stateDir=${stateDir}\\nconfigPath=${configPath}\\nagent=${JSON.stringify(agent)}\\nDiscord SecretRef=${JSON.stringify(writtenConfig.channels?.discord?.token)}`"
257+```
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。