@formthefog/stratus 2026.2.24 → 2026.3.19

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.
Files changed (75) hide show
  1. package/.github/sentinel/action.yml +100 -0
  2. package/.github/sentinel/dist/codebase.d.ts +3 -0
  3. package/.github/sentinel/dist/codebase.d.ts.map +1 -0
  4. package/.github/sentinel/dist/context.d.ts +6 -0
  5. package/.github/sentinel/dist/context.d.ts.map +1 -0
  6. package/.github/sentinel/dist/fixer.d.ts +6 -0
  7. package/.github/sentinel/dist/fixer.d.ts.map +1 -0
  8. package/.github/sentinel/dist/index.d.ts +1 -0
  9. package/.github/sentinel/dist/index.d.ts.map +1 -0
  10. package/.github/sentinel/dist/index.js +68808 -0
  11. package/.github/sentinel/dist/index.js.map +1 -0
  12. package/.github/sentinel/dist/licenses.txt +1152 -0
  13. package/.github/sentinel/dist/models/anthropic.d.ts +26 -0
  14. package/.github/sentinel/dist/models/anthropic.d.ts.map +1 -0
  15. package/.github/sentinel/dist/models/openai.d.ts +26 -0
  16. package/.github/sentinel/dist/models/openai.d.ts.map +1 -0
  17. package/.github/sentinel/dist/models/openrouter.d.ts +31 -0
  18. package/.github/sentinel/dist/models/openrouter.d.ts.map +1 -0
  19. package/.github/sentinel/dist/models/types.d.ts +37 -0
  20. package/.github/sentinel/dist/models/types.d.ts.map +1 -0
  21. package/.github/sentinel/dist/orchestrator.d.ts +3 -0
  22. package/.github/sentinel/dist/orchestrator.d.ts.map +1 -0
  23. package/.github/sentinel/dist/policy.d.ts +15 -0
  24. package/.github/sentinel/dist/policy.d.ts.map +1 -0
  25. package/.github/sentinel/dist/reporter.d.ts +8 -0
  26. package/.github/sentinel/dist/reporter.d.ts.map +1 -0
  27. package/.github/sentinel/dist/responder.d.ts +6 -0
  28. package/.github/sentinel/dist/responder.d.ts.map +1 -0
  29. package/.github/sentinel/dist/router.d.ts +2 -0
  30. package/.github/sentinel/dist/router.d.ts.map +1 -0
  31. package/.github/sentinel/dist/schemas/config.d.ts +195 -0
  32. package/.github/sentinel/dist/schemas/config.d.ts.map +1 -0
  33. package/.github/sentinel/dist/schemas/fix.d.ts +130 -0
  34. package/.github/sentinel/dist/schemas/fix.d.ts.map +1 -0
  35. package/.github/sentinel/dist/schemas/review.d.ts +275 -0
  36. package/.github/sentinel/dist/schemas/review.d.ts.map +1 -0
  37. package/.github/sentinel/dist/sourcemap-register.js +1 -0
  38. package/.github/sentinel/dist/subway.d.ts +31 -0
  39. package/.github/sentinel/dist/subway.d.ts.map +1 -0
  40. package/.github/sentinel/dist/types.d.ts +210 -0
  41. package/.github/sentinel/dist/types.d.ts.map +1 -0
  42. package/.github/sentinel/package-lock.json +2389 -0
  43. package/.github/sentinel/package.json +29 -0
  44. package/.github/sentinel/src/codebase.ts +265 -0
  45. package/.github/sentinel/src/context.ts +182 -0
  46. package/.github/sentinel/src/fixer.ts +353 -0
  47. package/.github/sentinel/src/index.ts +263 -0
  48. package/.github/sentinel/src/models/anthropic.ts +244 -0
  49. package/.github/sentinel/src/models/openai.ts +242 -0
  50. package/.github/sentinel/src/models/openrouter.ts +319 -0
  51. package/.github/sentinel/src/models/types.ts +35 -0
  52. package/.github/sentinel/src/orchestrator.ts +287 -0
  53. package/.github/sentinel/src/policy.ts +133 -0
  54. package/.github/sentinel/src/reporter.ts +666 -0
  55. package/.github/sentinel/src/responder.ts +156 -0
  56. package/.github/sentinel/src/router.ts +308 -0
  57. package/.github/sentinel/src/schemas/config.ts +84 -0
  58. package/.github/sentinel/src/schemas/fix.ts +44 -0
  59. package/.github/sentinel/src/schemas/review.ts +73 -0
  60. package/.github/sentinel/src/subway.ts +250 -0
  61. package/.github/sentinel/src/types.ts +234 -0
  62. package/.github/sentinel/tsconfig.json +19 -0
  63. package/.github/sentinel.yml +34 -0
  64. package/.github/workflows/sentinel.yml +55 -0
  65. package/README.md +88 -102
  66. package/SECURITY.md +21 -10
  67. package/TROUBLESHOOTING.md +2 -2
  68. package/index.ts +219 -109
  69. package/openclaw.plugin.json +50 -26
  70. package/package.json +1 -1
  71. package/skills/stratus-info/SKILL.md +70 -10
  72. package/src/client.ts +78 -18
  73. package/src/config.ts +29 -8
  74. package/src/setup.ts +53 -61
  75. package/src/types.ts +11 -0
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: stratus-info
3
3
  description: Knowledge base about Stratus X1-AC world model system
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  author: Stratus Team
6
6
  ---
7
7
 
@@ -25,10 +25,12 @@ This is a **hybrid architecture** with two capabilities:
25
25
  - Predicts compressed representations, not raw outputs
26
26
  - Enables planning by simulating action sequences before executing
27
27
 
28
- ### 2. Policy Head (Action Selector): "What action achieves this goal?"
28
+ ### 2. Policy Head v3 (Action Selector): "What action achieves this goal?"
29
+ - 94.41% masked accuracy — brain-guided action sequencing
29
30
  - Predicts the best action given current state + goal state
31
+ - Returns `brain_confidence` and `brain_goal_proximity` scores
30
32
  - Fast decision-making for known patterns
31
- - Provides confidence scores (low confidence → escalate to LLM)
33
+ - Low confidence → escalate to LLM
32
34
 
33
35
  **Key Innovation:**
34
36
  Instead of just guessing the next action, Stratus can **simulate the outcome of multiple actions** and pick the one most likely to achieve the goal.
@@ -44,6 +46,7 @@ Agents learn from each other in real-time:
44
46
  - When one agent discovers an effective approach, that knowledge flows to all agents
45
47
  - **Continuous learning**: successful patterns get canonicalized and fine-tuned into the model
46
48
  - **Domain-specific fine-tunes** (e-commerce, dev tools, research, etc.) share learnings back to the base model
49
+ - **Hierarchical tool architecture**: Brain handles sub-agent routing (orchestrator → sub-agents with specialized tool sets)
47
50
 
48
51
  It's like a hive mind for AI agents — practical distributed learning at scale.
49
52
 
@@ -78,10 +81,35 @@ see → simulate outcomes → pick best action → act
78
81
 
79
82
  ---
80
83
 
84
+ ## Authentication & Keys
85
+
86
+ ### Zero-Config (Formation Pool)
87
+ No API key needed. Formation holds pooled OpenRouter keys as a universal fallback.
88
+ - 25% markup on usage
89
+ - Instant access to all 2050+ models on day 0
90
+ - No setup required
91
+
92
+ ### BYOK (Bring Your Own Key)
93
+ Set `STRATUS_API_KEY` to bypass the Formation pool (no markup).
94
+ - Keys must start with `stratus_sk_`
95
+ - Get yours at https://stratus.run
96
+
97
+ ### Inline Provider Keys
98
+ Pass provider keys per-request for direct BYOK passthrough:
99
+ - `openai_key` — OpenAI direct
100
+ - `anthropic_key` — Anthropic direct
101
+ - `gemini_key` — Google Gemini direct (also sent as `X-Google-Key` header)
102
+ - Three-tier priority: headers > body > vault
103
+
104
+ Responses include `key_source: "user"` or `key_source: "formation"` so you always know which path was used.
105
+
106
+ ---
107
+
81
108
  ## Available Models
82
109
 
83
- Stratus provides **75 models** in the format:
110
+ Stratus provides **2050+ models** dynamically discovered via OpenRouter at startup.
84
111
 
112
+ Model format:
85
113
  ```
86
114
  stratus-x1ac-{size}-{llm}
87
115
  ```
@@ -89,9 +117,10 @@ stratus-x1ac-{size}-{llm}
89
117
  **Sizes:** `small`, `base`, `large`, `xl`, `huge`
90
118
 
91
119
  **Recommended LLMs:**
92
- - `claude-sonnet-4-5` - Claude 4.5 Sonnet (recommended)
93
- - `gpt-4o` - GPT-4 Optimized
94
- - `claude-haiku-4-5` - Fast, cost-effective
120
+ - `claude-sonnet-4-5` Claude 4.5 Sonnet (recommended)
121
+ - `gpt-4o` GPT-4 Optimized
122
+ - `claude-haiku-4-5` Fast, cost-effective
123
+ - `gemini-2.0-flash` — High context, fast
95
124
 
96
125
  **Example:**
97
126
  ```bash
@@ -99,6 +128,8 @@ openclaw agent "Plan a multi-step research task" \
99
128
  --model stratus/stratus-x1ac-base-claude-sonnet-4-5
100
129
  ```
101
130
 
131
+ Use `/stratus models` to fetch the full live list from the API.
132
+
102
133
  ---
103
134
 
104
135
  ## Available Tools
@@ -121,7 +152,7 @@ Generate 768-dimensional semantic state embeddings.
121
152
  ```
122
153
 
123
154
  ### `stratus_rollout`
124
- Multi-step action sequence planning.
155
+ Multi-step action sequence planning via Policy Head v3.
125
156
 
126
157
  **Use cases:**
127
158
  - Task decomposition
@@ -129,6 +160,12 @@ Multi-step action sequence planning.
129
160
  - Goal-oriented reasoning
130
161
  - Multi-step workflows
131
162
 
163
+ **Response fields:**
164
+ - `steps` — ordered action sequence
165
+ - `metadata.brain_confidence` — how confident the brain is in the plan
166
+ - `metadata.brain_goal_proximity` — estimated closeness to goal state
167
+ - `metadata.key_source` — "user" or "formation"
168
+
132
169
  **Example:**
133
170
  ```typescript
134
171
  {
@@ -162,6 +199,27 @@ const response = await openai.chat.completions.create({
162
199
 
163
200
  Stratus handles planning, then routes execution to the specified LLM (GPT-4o, Claude, etc.).
164
201
 
202
+ Non-Stratus models (e.g. raw `gpt-4o`) bypass the world model pipeline entirely (LLM passthrough).
203
+
204
+ Tool limit: **1024 tools per request** (raised from 100).
205
+
206
+ ---
207
+
208
+ ## SDKs
209
+
210
+ - **TypeScript**: This OpenClaw plugin (`@formthefog/stratus`)
211
+ - **Python**: `pip install stratus-sdk-py` (v0.0.6, full TS SDK parity, 76 tests)
212
+ - **Pi Agent**: `pi-formation` package (7 curated X1-AC models for Pi coding agent)
213
+
214
+ ---
215
+
216
+ ## Billing
217
+
218
+ - **Signup credits**: 200 credits (20K units) for new users
219
+ - **Saved cards**: Stripe-backed auto top-up when balance is low
220
+ - **Subscriptions**: Monthly credit bundles (starter/pro/enterprise) — 25% more credits vs one-time
221
+ - **Formation pool**: 25% markup on pooled key usage; BYOK users pay no markup
222
+
165
223
  ---
166
224
 
167
225
  ## Common Misconceptions
@@ -171,6 +229,7 @@ Stratus handles planning, then routes execution to the specified LLM (GPT-4o, Cl
171
229
  | "Stratus is just Claude with extended reasoning" | Stratus is a world model that predicts action consequences + collective learning network |
172
230
  | "It's a language model" | It's a hybrid architecture (world model + policy head) that routes to LLMs for execution |
173
231
  | "It's an LLM wrapper" | It's a JEPA-based predictive system with its own training and inference pipeline |
232
+ | "You need an API key" | Formation pool provides zero-config access; BYOK is optional |
174
233
 
175
234
  ---
176
235
 
@@ -187,10 +246,10 @@ For full technical details, see:
187
246
 
188
247
  1. **Install plugin:**
189
248
  ```bash
190
- openclaw plugins install @hathbanger/stratus
249
+ openclaw plugins install @formthefog/stratus
191
250
  ```
192
251
 
193
- 2. **Set API key:**
252
+ 2. **(Optional) Set API key for BYOK:**
194
253
  ```bash
195
254
  export STRATUS_API_KEY=stratus_sk_your_key_here
196
255
  ```
@@ -215,6 +274,7 @@ For full technical details, see:
215
274
  - Research workflows
216
275
  - Complex decision-making with uncertain outcomes
217
276
  - Tasks requiring "what-if" simulation
277
+ - Large tool sets (up to 1024 tools)
218
278
 
219
279
  **Overkill for:**
220
280
  - Simple Q&A
package/src/client.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type {
2
2
  StratusEmbeddingsRequest,
3
3
  StratusEmbeddingsResponse,
4
+ StratusInlineKeys,
4
5
  StratusPluginConfig,
5
6
  StratusRolloutRequest,
6
7
  StratusRolloutResponse,
@@ -10,44 +11,74 @@ import type {
10
11
  * SECURITY MANIFEST
11
12
  *
12
13
  * Environment Variables Accessed:
13
- * - STRATUS_API_KEY: User's Stratus API key (optional, can use config instead)
14
+ * - STRATUS_API_KEY: User's Stratus API key (optional Formation pool used as fallback)
15
+ * - OPENAI_API_KEY: Optional inline key for BYOK passthrough
16
+ * - ANTHROPIC_API_KEY: Optional inline key for BYOK passthrough
17
+ * - GOOGLE_API_KEY: Optional inline key for BYOK passthrough (also sent as X-Google-Key header)
14
18
  *
15
19
  * Network Endpoints:
16
20
  * - https://api.stratus.run/v1/embeddings (POST)
17
21
  * - https://api.stratus.run/v1/rollout (POST)
22
+ * - https://api.stratus.run/v1/models (GET)
18
23
  *
19
24
  * Data Transmitted:
20
- * - Authorization header: Bearer token (Stratus API key)
21
- * - Request body: User-provided text, goals, and parameters
25
+ * - Authorization header: Bearer token (Stratus API key, when provided)
26
+ * - X-Google-Key header: Google API key (when provided)
27
+ * - Request body: User-provided text, goals, parameters, and optional inline LLM keys
22
28
  *
23
29
  * Data Retention:
24
30
  * - All data sent to Stratus API per their privacy policy: https://stratus.run/privacy
25
31
  * - No local storage of credentials beyond process memory
26
32
  *
27
33
  * Security:
28
- * - API key validated (must start with 'stratus_sk_')
34
+ * - API key validated when present (must start with 'stratus_sk_')
35
+ * - Keyless operation uses Formation pooled keys (25% markup)
29
36
  * - HTTPS-only connections
30
37
  * - Keys never logged or persisted to disk by this plugin
31
38
  */
32
39
 
33
40
  export interface StratusClientConfig {
34
- apiKey: string;
41
+ apiKey?: string;
35
42
  baseUrl: string;
43
+ inlineKeys?: StratusInlineKeys;
36
44
  }
37
45
 
38
46
  export class StratusClient {
39
47
  constructor(private config: StratusClientConfig) {}
40
48
 
49
+ private buildHeaders(): Record<string, string> {
50
+ const headers: Record<string, string> = {
51
+ "Content-Type": "application/json",
52
+ };
53
+
54
+ if (this.config.apiKey) {
55
+ headers["Authorization"] = `Bearer ${this.config.apiKey}`;
56
+ }
57
+
58
+ if (this.config.inlineKeys?.gemini_key) {
59
+ headers["X-Google-Key"] = this.config.inlineKeys.gemini_key;
60
+ }
61
+
62
+ return headers;
63
+ }
64
+
65
+ private buildInlineKeyBody(): Record<string, string> {
66
+ const body: Record<string, string> = {};
67
+ if (this.config.inlineKeys?.openai_key) body.openai_key = this.config.inlineKeys.openai_key;
68
+ if (this.config.inlineKeys?.anthropic_key) body.anthropic_key = this.config.inlineKeys.anthropic_key;
69
+ if (this.config.inlineKeys?.gemini_key) body.gemini_key = this.config.inlineKeys.gemini_key;
70
+ return body;
71
+ }
72
+
41
73
  private async request<T>(endpoint: string, body: unknown): Promise<T> {
42
74
  const url = `${this.config.baseUrl}${endpoint}`;
75
+ const inlineKeys = this.buildInlineKeyBody();
76
+ const mergedBody = { ...(body as Record<string, unknown>), ...inlineKeys };
43
77
 
44
78
  const response = await fetch(url, {
45
79
  method: "POST",
46
- headers: {
47
- Authorization: `Bearer ${this.config.apiKey}`,
48
- "Content-Type": "application/json",
49
- },
50
- body: JSON.stringify(body),
80
+ headers: this.buildHeaders(),
81
+ body: JSON.stringify(mergedBody),
51
82
  });
52
83
 
53
84
  if (!response.ok) {
@@ -76,23 +107,52 @@ export class StratusClient {
76
107
  return_intermediate: params.return_intermediate ?? true,
77
108
  });
78
109
  }
110
+
111
+ async listModels(): Promise<{ object: string; data: Array<{ id: string; object: string; created: number; owned_by: string }> }> {
112
+ const url = `${this.config.baseUrl}/v1/models`;
113
+ const headers: Record<string, string> = {};
114
+ if (this.config.apiKey) {
115
+ headers["Authorization"] = `Bearer ${this.config.apiKey}`;
116
+ }
117
+
118
+ const response = await fetch(url, {
119
+ method: "GET",
120
+ headers,
121
+ });
122
+
123
+ if (!response.ok) {
124
+ const errorText = await response.text();
125
+ throw new Error(
126
+ `Stratus API error (${response.status}): ${errorText || response.statusText}`,
127
+ );
128
+ }
129
+
130
+ return response.json();
131
+ }
79
132
  }
80
133
 
81
134
  export function createStratusClient(config: StratusPluginConfig | undefined): StratusClient {
82
135
  const apiKey = config?.apiKey || process.env.STRATUS_API_KEY;
83
136
  const baseUrl = config?.baseUrl || "https://api.stratus.run";
84
137
 
85
- if (!apiKey) {
86
- throw new Error(
87
- "Stratus API key not configured. Set STRATUS_API_KEY env var or plugins.stratus.apiKey in config.",
88
- );
89
- }
90
-
91
- if (!apiKey.startsWith("stratus_sk_")) {
138
+ if (apiKey && !apiKey.startsWith("stratus_sk_")) {
92
139
  throw new Error(
93
140
  `Invalid Stratus API key format. Expected key starting with 'stratus_sk_', got '${apiKey.substring(0, 10)}...'`,
94
141
  );
95
142
  }
96
143
 
97
- return new StratusClient({ apiKey, baseUrl });
144
+ const inlineKeys: StratusInlineKeys = {
145
+ ...config?.inlineKeys,
146
+ openai_key: config?.inlineKeys?.openai_key || process.env.OPENAI_API_KEY,
147
+ anthropic_key: config?.inlineKeys?.anthropic_key || process.env.ANTHROPIC_API_KEY,
148
+ gemini_key: config?.inlineKeys?.gemini_key || process.env.GOOGLE_API_KEY,
149
+ };
150
+
151
+ const hasAnyInlineKey = inlineKeys.openai_key || inlineKeys.anthropic_key || inlineKeys.gemini_key;
152
+
153
+ return new StratusClient({
154
+ apiKey: apiKey || undefined,
155
+ baseUrl,
156
+ inlineKeys: hasAnyInlineKey ? inlineKeys : undefined,
157
+ });
98
158
  }
package/src/config.ts CHANGED
@@ -3,12 +3,18 @@ import type { StratusPluginConfig } from "./types.js";
3
3
 
4
4
  export const StratusConfigSchema: OpenClawPluginConfigSchema = {
5
5
  parse(value: unknown): StratusPluginConfig {
6
- const raw =
6
+ const entry =
7
7
  value && typeof value === "object" && !Array.isArray(value)
8
8
  ? (value as Record<string, unknown>)
9
9
  : {};
10
10
 
11
- const enabled = typeof raw.enabled === "boolean" ? raw.enabled : true;
11
+ const enabled = typeof entry.enabled === "boolean" ? entry.enabled : true;
12
+
13
+ const raw =
14
+ entry.config && typeof entry.config === "object" && !Array.isArray(entry.config)
15
+ ? (entry.config as Record<string, unknown>)
16
+ : {};
17
+
12
18
  const apiKey = typeof raw.apiKey === "string" ? raw.apiKey : process.env.STRATUS_API_KEY;
13
19
  const baseUrl = typeof raw.baseUrl === "string" ? raw.baseUrl : "https://api.stratus.run";
14
20
 
@@ -37,10 +43,22 @@ export const StratusConfigSchema: OpenClawPluginConfigSchema = {
37
43
  ? (tools.rollout as Record<string, unknown>)
38
44
  : {};
39
45
 
46
+ const inlineKeysRaw =
47
+ raw.inlineKeys && typeof raw.inlineKeys === "object" && !Array.isArray(raw.inlineKeys)
48
+ ? (raw.inlineKeys as Record<string, unknown>)
49
+ : {};
50
+
51
+ const inlineKeys = {
52
+ openai_key: typeof inlineKeysRaw.openai_key === "string" ? inlineKeysRaw.openai_key : undefined,
53
+ anthropic_key: typeof inlineKeysRaw.anthropic_key === "string" ? inlineKeysRaw.anthropic_key : undefined,
54
+ gemini_key: typeof inlineKeysRaw.gemini_key === "string" ? inlineKeysRaw.gemini_key : undefined,
55
+ };
56
+
40
57
  return {
41
58
  enabled,
42
59
  apiKey,
43
60
  baseUrl,
61
+ inlineKeys,
44
62
  provider: {
45
63
  enabled: providerEnabled,
46
64
  defaultModel,
@@ -57,14 +75,17 @@ export const StratusConfigSchema: OpenClawPluginConfigSchema = {
57
75
  },
58
76
  uiHints: {
59
77
  enabled: { label: "Enabled" },
60
- apiKey: { label: "API Key", sensitive: true },
61
- baseUrl: { label: "Base URL", placeholder: "https://api.stratus.run" },
62
- "provider.enabled": { label: "Provider Enabled" },
63
- "provider.defaultModel": {
78
+ "config.apiKey": { label: "API Key", sensitive: true },
79
+ "config.baseUrl": { label: "Base URL", placeholder: "https://api.stratus.run" },
80
+ "config.inlineKeys.openai_key": { label: "OpenAI Key (BYOK)", sensitive: true },
81
+ "config.inlineKeys.anthropic_key": { label: "Anthropic Key (BYOK)", sensitive: true },
82
+ "config.inlineKeys.gemini_key": { label: "Google Gemini Key (BYOK)", sensitive: true },
83
+ "config.provider.enabled": { label: "Provider Enabled" },
84
+ "config.provider.defaultModel": {
64
85
  label: "Default Model",
65
86
  placeholder: "stratus-x1ac-base-claude-sonnet-4-5",
66
87
  },
67
- "tools.embeddings.enabled": { label: "Embeddings Tool Enabled" },
68
- "tools.rollout.enabled": { label: "Rollout Tool Enabled" },
88
+ "config.tools.embeddings.enabled": { label: "Embeddings Tool Enabled" },
89
+ "config.tools.rollout.enabled": { label: "Rollout Tool Enabled" },
69
90
  },
70
91
  };
package/src/setup.ts CHANGED
@@ -18,31 +18,28 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
18
18
  const details: string[] = [];
19
19
 
20
20
  try {
21
- // Step 1: Check for existing API key
22
21
  const apiKey = process.env.STRATUS_API_KEY;
23
-
24
- if (!apiKey) {
25
- return {
26
- success: false,
27
- message: "STRATUS_API_KEY not found",
28
- details: [
29
- "Please set your Stratus API key as an environment variable:",
30
- "",
31
- " export STRATUS_API_KEY=stratus_sk_your_key_here",
32
- "",
33
- "Or add to your shell config (~/.zshrc or ~/.bashrc):",
34
- "",
35
- " echo 'export STRATUS_API_KEY=stratus_sk_your_key_here' >> ~/.zshrc",
36
- " source ~/.zshrc",
37
- "",
38
- "Get your API key at: https://stratus.run",
39
- ],
40
- };
22
+ const usingFormationPool = !apiKey;
23
+
24
+ if (apiKey) {
25
+ if (!apiKey.startsWith("stratus_sk_")) {
26
+ return {
27
+ success: false,
28
+ message: "Invalid STRATUS_API_KEY format",
29
+ details: [
30
+ "API key must start with 'stratus_sk_'",
31
+ "",
32
+ "Get your API key at: https://stratus.run",
33
+ ],
34
+ };
35
+ }
36
+ details.push("✓ Using STRATUS_API_KEY from environment (BYOK — no markup)");
37
+ } else {
38
+ details.push("✓ No API key found — using Formation pooled keys (zero-config)");
39
+ details.push(" ℹ Formation pool applies a 25% markup on usage");
40
+ details.push(" 💡 Set STRATUS_API_KEY for BYOK (no markup)");
41
41
  }
42
42
 
43
- details.push("✓ Using STRATUS_API_KEY from environment");
44
-
45
- // Paths
46
43
  const homeDir = os.homedir();
47
44
  const openclawConfig = path.join(homeDir, ".openclaw", "openclaw.json");
48
45
  const authProfiles = path.join(
@@ -54,25 +51,18 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
54
51
  "auth-profiles.json"
55
52
  );
56
53
 
57
- // Step 2: Update OpenClaw config
58
54
  details.push("🔧 Updating OpenClaw configuration...");
59
55
 
60
56
  if (fs.existsSync(openclawConfig)) {
61
- // Backup
62
57
  const backupPath = `${openclawConfig}.backup-${Date.now()}`;
63
58
  fs.copyFileSync(openclawConfig, backupPath);
64
59
  details.push(` 📦 Created backup: ${path.basename(backupPath)}`);
65
60
 
66
- // Read and update config
67
61
  const config = JSON.parse(fs.readFileSync(openclawConfig, "utf-8"));
68
62
 
69
- // Add models.providers.stratus if not present
70
- if (!config.models) {
71
- config.models = {};
72
- }
73
- if (!config.models.providers) {
74
- config.models.providers = {};
75
- }
63
+ if (!config.models) config.models = {};
64
+ if (!config.models.providers) config.models.providers = {};
65
+
76
66
  if (!config.models.providers.stratus) {
77
67
  config.models.providers.stratus = {
78
68
  baseUrl: "https://api.stratus.run/v1",
@@ -94,24 +84,11 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
94
84
  details.push(" ✓ Stratus provider already configured");
95
85
  }
96
86
 
97
- // Add model alias
98
- if (!config.agents?.defaults?.models) {
99
- if (!config.agents) config.agents = {};
100
- if (!config.agents.defaults) config.agents.defaults = {};
101
- if (!config.agents.defaults.models) config.agents.defaults.models = {};
102
- }
103
-
104
- if (!config.agents.defaults.models["stratus/stratus-x1ac-base-claude-sonnet-4-5"]) {
105
- config.agents.defaults.models["stratus/stratus-x1ac-base-claude-sonnet-4-5"] = {
106
- alias: "stratus",
107
- params: {},
108
- };
109
- details.push(" ✓ Added model alias 'stratus'");
110
- } else {
111
- details.push(" ✓ Model alias already configured");
87
+ if (config.agents?.defaults?.models?.["stratus/stratus-x1ac-base-claude-sonnet-4-5"]) {
88
+ delete config.agents.defaults.models["stratus/stratus-x1ac-base-claude-sonnet-4-5"];
89
+ details.push(" ✓ Removed restrictive model alias (allows all Stratus models)");
112
90
  }
113
91
 
114
- // Write updated config
115
92
  fs.writeFileSync(openclawConfig, JSON.stringify(config, null, 2));
116
93
  } else {
117
94
  return {
@@ -125,7 +102,6 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
125
102
  };
126
103
  }
127
104
 
128
- // Step 3: Update auth profiles
129
105
  details.push("🔑 Configuring authentication...");
130
106
 
131
107
  const authDir = path.dirname(authProfiles);
@@ -135,14 +111,10 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
135
111
 
136
112
  let authConfig: any;
137
113
  if (fs.existsSync(authProfiles)) {
138
- // Backup
139
114
  const backupPath = `${authProfiles}.backup-${Date.now()}`;
140
115
  fs.copyFileSync(authProfiles, backupPath);
141
-
142
- // Update existing
143
116
  authConfig = JSON.parse(fs.readFileSync(authProfiles, "utf-8"));
144
117
  } else {
145
- // Create new
146
118
  authConfig = {
147
119
  version: 1,
148
120
  profiles: {},
@@ -151,16 +123,26 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
151
123
  };
152
124
  }
153
125
 
154
- // Add Stratus profile
155
- authConfig.profiles["stratus:default"] = {
156
- type: "api_key",
157
- provider: "stratus",
158
- key: apiKey,
159
- };
160
- authConfig.lastGood.stratus = "stratus:default";
126
+ if (apiKey) {
127
+ authConfig.profiles["stratus:default"] = {
128
+ type: "api_key",
129
+ provider: "stratus",
130
+ key: apiKey,
131
+ };
132
+ authConfig.lastGood.stratus = "stratus:default";
133
+ details.push(" ✓ Updated auth profile (BYOK)");
134
+ } else {
135
+ authConfig.profiles["stratus:formation-pool"] = {
136
+ type: "formation_pool",
137
+ provider: "stratus",
138
+ };
139
+ authConfig.lastGood.stratus = "stratus:formation-pool";
140
+ details.push(" ✓ Configured Formation pool auth (zero-config)");
141
+ }
161
142
 
162
143
  fs.writeFileSync(authProfiles, JSON.stringify(authConfig, null, 2));
163
- details.push(" ✓ Updated auth profile");
144
+
145
+ const modeLabel = usingFormationPool ? "Formation pool (zero-config)" : "BYOK (no markup)";
164
146
 
165
147
  return {
166
148
  success: true,
@@ -168,6 +150,8 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
168
150
  details: [
169
151
  ...details,
170
152
  "",
153
+ `🔒 Auth mode: ${modeLabel}`,
154
+ "",
171
155
  "🎯 Next steps:",
172
156
  " 1. Restart gateway: openclaw gateway stop && openclaw gateway install",
173
157
  " 2. Verify: openclaw models list | grep stratus",
@@ -176,6 +160,14 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
176
160
  "📚 Available tools:",
177
161
  " • stratus_embeddings - Generate semantic embeddings",
178
162
  " • stratus_rollout - Multi-step task planning",
163
+ ...(usingFormationPool
164
+ ? [
165
+ "",
166
+ "💡 To remove the 25% Formation markup, set your own key:",
167
+ " export STRATUS_API_KEY=stratus_sk_your_key_here",
168
+ " Then re-run /stratus setup",
169
+ ]
170
+ : []),
179
171
  ],
180
172
  };
181
173
  } catch (error) {
package/src/types.ts CHANGED
@@ -38,13 +38,24 @@ export interface StratusRolloutResponse {
38
38
  metadata?: {
39
39
  model: string;
40
40
  duration_ms?: number;
41
+ brain_confidence?: number;
42
+ brain_goal_proximity?: number;
43
+ key_source?: "user" | "formation";
44
+ formation_markup_applied?: number;
41
45
  };
42
46
  }
43
47
 
48
+ export interface StratusInlineKeys {
49
+ openai_key?: string;
50
+ anthropic_key?: string;
51
+ gemini_key?: string;
52
+ }
53
+
44
54
  export interface StratusPluginConfig {
45
55
  enabled?: boolean;
46
56
  apiKey?: string;
47
57
  baseUrl?: string;
58
+ inlineKeys?: StratusInlineKeys;
48
59
  provider?: {
49
60
  enabled?: boolean;
50
61
  defaultModel?: string;