create-snipara 1.3.9 → 1.3.12

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 (3) hide show
  1. package/README.md +67 -41
  2. package/dist/index.js +293 -157
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -48,10 +48,10 @@ The product surfaces remain:
48
48
  - Hosted MCP for LLM agents, context, and reviewed memory
49
49
  - HTTP API / SDK for apps, integrators, backends, and pipelines
50
50
 
51
- The CLI can wire local helpers around those surfaces:
51
+ The default CLI path wires the local companion around those surfaces:
52
52
 
53
- - `snipara-companion` for local `rlm-hook` workflows when you want them
54
- - `rlm-runtime` for optional local code execution
53
+ - `snipara-companion` for local workflow commands and managed phase commits; legacy `rlm-hook` commands remain compatible
54
+ - `snipara-sandbox` for optional local code execution
55
55
  - local config, env files, hook scripts, and a project companion pack
56
56
  - `snipara-mcp` only for local stdio compatibility, development, or testing
57
57
 
@@ -59,14 +59,14 @@ The CLI can wire local helpers around those surfaces:
59
59
 
60
60
  The CLI now works around explicit install profiles:
61
61
 
62
- | Profile | What it installs | Best for |
63
- | ------------------ | ----------------------------------------- | --------------------------------------------------- |
64
- | `hosted-only` | Hosted MCP config only | Default: agents without local helper workflows |
65
- | `hosted-companion` | MCP + `snipara-companion` | Hook-heavy clients that want local helper workflows |
66
- | `full-stack` | MCP + `snipara-companion` + `rlm-runtime` | Hosted context plus local execution |
67
- | `runtime-only` | `rlm-runtime` only | Local execution without hosted API |
62
+ | Profile | What it installs | Best for |
63
+ | ------------------ | --------------------------------------------- | --------------------------------------------------- |
64
+ | `hosted-companion` | MCP + `snipara-companion` | Default: hosted context plus managed local workflow |
65
+ | `hosted-only` | Hosted MCP config only | Locked-down or minimal environments |
66
+ | `full-stack` | MCP + `snipara-companion` + `snipara-sandbox` | Hosted context plus sandboxed local execution |
67
+ | `runtime-only` | `snipara-sandbox` only | Local execution without hosted API |
68
68
 
69
- Default profile: `hosted-only`
69
+ Default profile: `hosted-companion`
70
70
 
71
71
  ## Free Account Fit
72
72
 
@@ -76,7 +76,7 @@ Free onboarding is now **Context + Memory**, not Context-only:
76
76
  - Memory Free: reviewed hosted memories for continuity across sessions
77
77
  - Hosted MCP: direct connection for Claude Code, Codex, Cursor, ChatGPT Desktop, and other MCP clients
78
78
 
79
- The CLI opens a browser device-flow login when the user does not already have a key, auto-provisions the free Context + Memory account when needed, then writes the returned project key into the local MCP config.
79
+ The CLI opens a browser device-flow login when the user does not already have a key, auto-provisions the free Context + Memory account when needed, then writes the returned API key into the local MCP config.
80
80
 
81
81
  ## The Two Approval Paths
82
82
 
@@ -99,10 +99,10 @@ That distinction matters:
99
99
  - opens the browser device-flow free Context + Memory account flow when needed
100
100
  - writes Hosted MCP configuration
101
101
  - detects a GitHub remote and can open the Snipara GitHub App automation path
102
- - installs `snipara-companion` when the selected profile needs local helper workflows
103
- - installs optional `rlm-runtime`
102
+ - installs `snipara-companion` by default for local managed workflows
103
+ - installs optional `snipara-sandbox`
104
104
  - configures `.mcp.json`
105
- - generates merge-ready AI agent templates in `.snipara/templates/`, including Pro+ symbol-card and code-impact guidance for paid Context plans
105
+ - generates merge-ready AI agent templates in `.snipara/templates/`, including Pro+ symbol-card, code-impact, and managed workflow guidance for paid Context plans
106
106
  - creates `AGENTS.md`, `CLAUDE.md`, `.cursor/rules/snipara.mdc`, and `.codex/config.toml` when those files do not already exist
107
107
  - updates `.env`, `.env.local`, and `.env.example`
108
108
  - generates `.snipara/companion/README.md`
@@ -131,12 +131,13 @@ npx create-snipara
131
131
  The interactive flow now asks for:
132
132
 
133
133
  - project slug
134
- - API key path: project key, team key, free signup, or add key later
134
+ - API key path: existing API key, free signup, or add key later
135
135
  - AI client
136
136
 
137
- By default, this stays on the recommended `hosted-only` setup. Add
138
- `--advanced` when you want profile selection, project id entry, hook prompts,
139
- GitHub automation prompts, or runtime provider prompts.
137
+ By default, this uses the recommended `hosted-companion` setup: hosted MCP plus
138
+ the local `snipara-companion` workflow helper. Legacy `rlm-hook` commands remain
139
+ compatible. Add `--advanced` when you want profile selection, project id entry,
140
+ hook prompts, GitHub automation prompts, or sandbox provider prompts.
140
141
 
141
142
  The advanced flow asks for:
142
143
 
@@ -144,7 +145,7 @@ The advanced flow asks for:
144
145
  - optional project id
145
146
  - whether hooks should be generated
146
147
  - whether to open GitHub repository automation when a GitHub remote is detected
147
- - optional runtime provider config when `rlm-runtime` is installed
148
+ - optional sandbox provider config when `snipara-sandbox` is installed
148
149
 
149
150
  The generated agent templates cover:
150
151
 
@@ -154,6 +155,17 @@ The generated agent templates cover:
154
155
  - Codex `.codex/config.toml` snippet
155
156
  - ChatGPT/OpenAI HTTP MCP snippet
156
157
 
158
+ When `snipara-companion` is installed, the companion pack also includes the compaction-safe managed workflow:
159
+
160
+ ```bash
161
+ snipara-companion workflow start --goal "ship auth hardening" --plan-file ./plan.md
162
+ snipara-companion workflow phase-start context
163
+ snipara-companion workflow run --mode full --include-session-context --query "load auth context"
164
+ snipara-companion code impact --changed-files src/auth.ts tests/auth.test.ts --diff-summary "auth hardening"
165
+ snipara-companion workflow phase-commit context --summary "Loaded context and mapped impacted files" --files src/auth.ts
166
+ snipara-companion final-commit --summary "Shipped auth hardening and tests" --files src/auth.ts tests/auth.test.ts
167
+ ```
168
+
157
169
  ## Main Commands
158
170
 
159
171
  ### Install or initialize
@@ -175,7 +187,7 @@ Writes `.snipara/companion/doctor.json` and validates:
175
187
 
176
188
  - local config files
177
189
  - companion CLI presence
178
- - runtime CLI presence
190
+ - Snipara Sandbox CLI presence
179
191
  - environment files
180
192
  - hosted MCP reachability when a live API key is available
181
193
 
@@ -247,15 +259,15 @@ That keeps business truth review separate from agent onboarding.
247
259
 
248
260
  ```bash
249
261
  # Use an explicit install profile
250
- npx create-snipara --profile hosted-only
251
262
  npx create-snipara --profile hosted-companion
263
+ npx create-snipara --profile hosted-only
252
264
  npx create-snipara --profile full-stack
253
265
  npx create-snipara --advanced
254
266
 
255
- # Runtime-only local execution
267
+ # Sandbox-only local execution
256
268
  npx create-snipara --runtime-only
257
269
 
258
- # Non-interactive setup
270
+ # Non-interactive setup with an existing API key
259
271
  npx create-snipara -y --api-key rlm_xxx --slug my-project
260
272
 
261
273
  # Open GitHub automation after setup when a GitHub remote is detected
@@ -271,6 +283,7 @@ npx create-snipara --skip-github
271
283
 
272
284
  # Force extra layers during maintenance
273
285
  npx create-snipara repair --with-hooks
286
+ npx create-snipara repair --with-runtime
274
287
  npx create-snipara upgrade --with-runtime
275
288
  ```
276
289
 
@@ -279,18 +292,19 @@ npx create-snipara upgrade --with-runtime
279
292
  The intended split is:
280
293
 
281
294
  - `create-snipara`: Context + Memory onboarding, auth, config, inspect, repair, and upgrade
282
- - `snipara-companion`: optional ongoing local runtime workflows through `rlm-hook`
295
+ - `snipara-companion`: default local workflow helper; legacy `rlm-hook` commands remain compatible
283
296
  - `snipara-mcp`: local stdio bridge, client-package development, compatibility, and testing
284
- - `rlm-runtime`: optional local execution engine
297
+ - `snipara-sandbox`: optional local execution engine
285
298
 
286
299
  ## Codex Setup
287
300
 
288
- For Codex, keep the setup minimal:
301
+ For Codex, keep Hosted MCP as the core path and let companion add workflow
302
+ ergonomics:
289
303
 
290
304
  - use Hosted MCP as the core Snipara surface
291
305
  - use `AGENTS.md` for project instructions
292
- - choose `hosted-only` if you do not need local helper workflows
293
- - add `snipara-companion` only if you explicitly want the local helper CLI
306
+ - use the default `hosted-companion` path when you want compaction-safe local phase commits
307
+ - choose `hosted-only` or `--skip-companion` only in locked-down environments
294
308
  - use local `snipara-mcp` only for stdio compatibility, development, or tests
295
309
 
296
310
  Codex does not require hook presets to use Snipara successfully.
@@ -310,8 +324,8 @@ This pack is meant to be the local source of truth for machine-level setup. When
310
324
  such as:
311
325
 
312
326
  ```bash
313
- rlm-hook onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json
314
- rlm-hook onboard-folder ./client-export --source-provider local_folder --apply
327
+ snipara-companion onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json
328
+ snipara-companion onboard-folder ./client-export --source-provider local_folder --apply
315
329
  ```
316
330
 
317
331
  Use this for dashboardless business-context imports after an LLM client has
@@ -342,23 +356,35 @@ Recommended explanation to users:
342
356
 
343
357
  ## API Key Requirements
344
358
 
345
- | Tooling | Snipara API key | LLM API key |
346
- | ------------------------------------ | -------------------------- | ----------- |
347
- | Hosted MCP queries | Required | Not needed |
348
- | Memory / planning tools | Required with memory scope | Not needed |
349
- | `snipara-companion` hosted workflows | Optional | Not needed |
350
- | `rlm-runtime` `execute_python` MCP | Not needed | Not needed |
351
- | `rlm run` / `rlm agent` CLI | Optional for context | Required |
359
+ Existing manual API keys passed to `create-snipara --api-key` should start with `rlm_`.
360
+ When `create-snipara` provisions a new account through the browser flow, Snipara returns a
361
+ new `snp-` key from the current hosted API.
362
+
363
+ | Tooling | Snipara API key | LLM API key |
364
+ | --------------------------------------------------- | -------------------------- | ----------- |
365
+ | Hosted MCP queries | Required | Not needed |
366
+ | Memory / planning tools | Required with memory scope | Not needed |
367
+ | `snipara-companion` hosted workflows | Optional | Not needed |
368
+ | `snipara-sandbox` `execute_python` MCP | Not needed | Not needed |
369
+ | `snipara-sandbox run` / `snipara-sandbox agent` CLI | Optional for context | Required |
352
370
 
353
371
  ## Example Flows
354
372
 
355
- ### Default hosted setup
373
+ ### Default managed hosted setup
374
+
375
+ ```bash
376
+ npx create-snipara
377
+ ```
378
+
379
+ Best when the user wants Hosted MCP Context + Memory plus `snipara-companion` managed workflows.
380
+
381
+ ### Minimal hosted setup
356
382
 
357
383
  ```bash
358
384
  npx create-snipara --profile hosted-only
359
385
  ```
360
386
 
361
- Best when the user only wants Hosted MCP Context + Memory.
387
+ Best when the user only wants Hosted MCP Context + Memory and cannot install local helper tooling.
362
388
 
363
389
  ### Full local stack
364
390
 
@@ -366,7 +392,7 @@ Best when the user only wants Hosted MCP Context + Memory.
366
392
  npx create-snipara --profile full-stack --advanced
367
393
  ```
368
394
 
369
- Best when the user also wants `snipara-companion` and `rlm-runtime`.
395
+ Best when the user also wants sandboxed `snipara-sandbox` execution.
370
396
 
371
397
  ### Connect the current repository
372
398
 
@@ -411,7 +437,7 @@ npx create-snipara print-config --json
411
437
  When testing a locally packed tarball, use `npm exec --package` instead of `npx`, for example:
412
438
 
413
439
  ```bash
414
- npm exec --package ./create-snipara-1.3.9.tgz create-snipara -- --help
440
+ npm exec --package ./create-snipara-1.3.12.tgz create-snipara -- --help
415
441
  ```
416
442
 
417
443
  This avoids `npx` resolution issues with unpublished tarballs.
package/dist/index.js CHANGED
@@ -9,12 +9,18 @@ import fs from "fs";
9
9
  import path from "path";
10
10
  import { execSync, spawn } from "child_process";
11
11
  import { homedir } from "os";
12
- var VERSION = "1.3.9";
12
+ var VERSION = "1.3.12";
13
13
  var BASE_URL = "https://www.snipara.com";
14
14
  var API_URL = "https://api.snipara.com";
15
15
  var COMPANION_PACKAGE_NAME = "snipara-companion";
16
+ var COMPANION_COMMAND_NAME = "snipara-companion";
17
+ var LEGACY_COMPANION_COMMAND_NAME = "rlm-hook";
16
18
  var MCP_PACKAGE_NAME = "snipara-mcp";
17
- var RUNTIME_PACKAGE_NAME = "rlm-runtime[all]";
19
+ var SANDBOX_PACKAGE_NAME = "snipara-sandbox[all]";
20
+ var SANDBOX_SERVER_NAME = "snipara-sandbox";
21
+ var LEGACY_RUNTIME_SERVER_NAME = "rlm-runtime";
22
+ var SANDBOX_COMMAND_NAME = "snipara-sandbox";
23
+ var LEGACY_SANDBOX_COMMAND_NAME = "rlm";
18
24
  var DEVICE_CLIENT_ID = "create-snipara";
19
25
  var DeviceAuthorizationAborted = class extends Error {
20
26
  };
@@ -26,11 +32,11 @@ function getCompanionInitClientFlag(aiClient) {
26
32
  }
27
33
  function buildProgram() {
28
34
  const program = new Command();
29
- program.name("create-snipara").description("Scaffold hosted Snipara MCP config plus optional local helper workflows").version(VERSION);
30
- program.command("init").description("Install and configure Snipara for this project").option("--api-key <key>", "Snipara project API key").option("--team-key <key>", "Snipara team API key").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID").option("--advanced", "Show advanced profile, project id, hooks, GitHub, and runtime prompts").option(
35
+ program.name("create-snipara").description("Scaffold hosted Snipara MCP config plus companion workflow helpers").version(VERSION);
36
+ program.command("init").description("Install and configure Snipara for this project").option("--api-key <key>", "Snipara API key").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID").option("--advanced", "Show advanced profile, project id, hooks, GitHub, and sandbox prompts").option(
31
37
  "--profile <profile>",
32
38
  "Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
33
- ).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip rlm-runtime installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").option("--github", "Open GitHub repository automation setup when a git remote is detected").option("--skip-github", "Skip the GitHub automation prompt").option("--github-path <path>", "Optional GitHub path filter for the initial repository sync").option("--runtime-only", "Install only RLM-Runtime").option("-y, --yes", "Accept defaults without prompting").action(async (options) => {
39
+ ).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip snipara-sandbox installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").option("--github", "Open GitHub repository automation setup when a git remote is detected").option("--skip-github", "Skip the GitHub automation prompt").option("--github-path <path>", "Optional GitHub path filter for the initial repository sync").option("--runtime-only", "Install only Snipara Sandbox").option("-y, --yes", "Accept defaults without prompting").action(async (options) => {
34
40
  printBanner();
35
41
  await runInit(options);
36
42
  });
@@ -38,11 +44,11 @@ function buildProgram() {
38
44
  printBanner();
39
45
  await runDoctor(options);
40
46
  });
41
- program.command("repair").description("Rebuild local Snipara config and re-run validation").option("--api-key <key>", "Snipara project API key override").option("--team-key <key>", "Snipara team API key override").option("--slug <slug>", "Project slug override").option("--project-id <id>", "Project ID override").option("--profile <profile>", "Target install profile").option("--with-hooks", "Force hook generation").option("--with-runtime", "Force runtime server/config").option("--with-mcp", "Force MCP config").option("--with-companion", "Force companion pack generation").action(async (options) => {
47
+ program.command("repair").description("Rebuild local Snipara config and re-run validation").option("--api-key <key>", "Snipara API key override").option("--slug <slug>", "Project slug override").option("--project-id <id>", "Project ID override").option("--profile <profile>", "Target install profile").option("--with-hooks", "Force hook generation").option("--with-runtime", "Force Snipara Sandbox server/config").option("--with-mcp", "Force MCP config").option("--with-companion", "Force companion pack generation").action(async (options) => {
42
48
  printBanner();
43
49
  await runRepair(options);
44
50
  });
45
- program.command("upgrade").description("Upgrade installed Snipara local components").option("--with-hooks", "Refresh hooks after upgrade").option("--with-runtime", "Upgrade runtime even if not detected").option("--with-mcp", "Upgrade snipara-mcp even if not detected").option("--with-companion", "Upgrade companion even if not detected").action(async (options) => {
51
+ program.command("upgrade").description("Upgrade installed Snipara local components").option("--with-hooks", "Refresh hooks after upgrade").option("--with-runtime", "Upgrade Snipara Sandbox even if not detected").option("--with-mcp", "Upgrade snipara-mcp even if not detected").option("--with-companion", "Upgrade companion even if not detected").action(async (options) => {
46
52
  printBanner();
47
53
  await runUpgrade(options);
48
54
  });
@@ -58,10 +64,10 @@ function buildProgram() {
58
64
  return program;
59
65
  }
60
66
  function addSharedRootOptions(program) {
61
- program.option("--api-key <key>", "Snipara project API key").option("--team-key <key>", "Snipara team API key").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID").option("--advanced", "Show advanced profile, project id, hooks, GitHub, and runtime prompts").option(
67
+ program.option("--api-key <key>", "Snipara API key").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID").option("--advanced", "Show advanced profile, project id, hooks, GitHub, and sandbox prompts").option(
62
68
  "--profile <profile>",
63
69
  "Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
64
- ).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip rlm-runtime installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").option("--github", "Open GitHub repository automation setup when a git remote is detected").option("--skip-github", "Skip the GitHub automation prompt").option("--github-path <path>", "Optional GitHub path filter for the initial repository sync").option("--runtime-only", "Install only RLM-Runtime").option("-y, --yes", "Accept defaults without prompting");
70
+ ).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip snipara-sandbox installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").option("--github", "Open GitHub repository automation setup when a git remote is detected").option("--skip-github", "Skip the GitHub automation prompt").option("--github-path <path>", "Optional GitHub path filter for the initial repository sync").option("--runtime-only", "Install only Snipara Sandbox").option("-y, --yes", "Accept defaults without prompting");
65
71
  }
66
72
  async function main() {
67
73
  const program = buildProgram();
@@ -81,7 +87,6 @@ function parseInitOptionsFromArgv(args) {
81
87
  const parsed = {};
82
88
  const valueFlags = {
83
89
  "--api-key": "apiKey",
84
- "--team-key": "teamKey",
85
90
  "--slug": "slug",
86
91
  "--project-id": "projectId",
87
92
  "--profile": "profile",
@@ -145,8 +150,8 @@ async function runInit(options) {
145
150
  if (answers.configureGitHub && answers.githubRepo) {
146
151
  await openGitHubAutomation(answers);
147
152
  }
148
- if (answers.runRlmInit && answers.installRuntime) {
149
- await runRlmInit();
153
+ if (answers.runSandboxInit && answers.installRuntime) {
154
+ await runSandboxInit();
150
155
  }
151
156
  }
152
157
  async function runDoctor(options) {
@@ -223,7 +228,7 @@ async function runPrintConfig(options) {
223
228
  ` Hosted MCP config: ${answers.profile !== "runtime-only" ? "enabled" : "disabled"}`
224
229
  );
225
230
  console.log(` Local snipara-mcp package: ${answers.installMcp ? "enabled" : "disabled"}`);
226
- console.log(` Runtime: ${answers.installRuntime ? "enabled" : "disabled"}`);
231
+ console.log(` Snipara Sandbox: ${answers.installRuntime ? "enabled" : "disabled"}`);
227
232
  console.log(` Hooks: ${answers.installHooks ? "enabled" : "disabled"}`);
228
233
  console.log(` Existing .mcp.json: ${detection.files.mcpConfig ? "yes" : "no"}`);
229
234
  console.log(` Companion pack: ${detection.files.sniparaCompanionPack ? "yes" : "no"}`);
@@ -239,7 +244,7 @@ function printBanner() {
239
244
  \u2551 \u2022 Hosted MCP for LLM agents \u2551
240
245
  \u2551 \u2022 Free account path with hosted context and reviewed memory \u2551
241
246
  \u2551 \u2022 API / SDK for product integrations \u2551
242
- \u2551 \u2022 Optional local companion and runtime helpers \u2551
247
+ \u2551 \u2022 Optional local companion and Snipara Sandbox helpers \u2551
243
248
  \u2551 \u2022 One CLI for auth, config, doctor, repair, and upgrade \u2551
244
249
  \u2551 \u2551
245
250
  \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
@@ -267,12 +272,16 @@ async function gatherConfiguration(options) {
267
272
  detectedProjectId = existingConfig.projectId || "";
268
273
  }
269
274
  const initialProfile = resolveRequestedProfile(options);
275
+ const providedApiKey = options.apiKey?.trim();
276
+ if (providedApiKey && !isManualApiKey(providedApiKey)) {
277
+ throw new Error(manualApiKeyValidationMessage());
278
+ }
270
279
  if (options.yes) {
271
280
  return buildAnswersFromProfile({
272
281
  projectSlug: options.slug || detectedSlug || "my-project",
273
282
  projectId: options.projectId || detectedProjectId,
274
- apiKey: options.teamKey || options.apiKey || "YOUR_API_KEY_HERE",
275
- apiKeyType: options.teamKey ? "team" : options.apiKey ? "project" : "none",
283
+ apiKey: providedApiKey || "YOUR_API_KEY_HERE",
284
+ apiKeyType: providedApiKey ? "api" : "none",
276
285
  profile: initialProfile,
277
286
  aiClient: detectedClient,
278
287
  skipCompanion: !!options.skipCompanion,
@@ -306,19 +315,14 @@ async function gatherConfiguration(options) {
306
315
  initial: options.projectId || detectedProjectId || ""
307
316
  },
308
317
  {
309
- type: (_, values) => values.profile === "runtime-only" || options.apiKey || options.teamKey ? null : "select",
318
+ type: (_, values) => values.profile === "runtime-only" || providedApiKey ? null : "select",
310
319
  name: "apiKeyType",
311
- message: "What type of API key do you have?",
320
+ message: "How do you want to add your Snipara API key?",
312
321
  choices: [
313
322
  {
314
- title: "Project API key",
315
- value: "project",
316
- description: "Access to a single project"
317
- },
318
- {
319
- title: "Team API key",
320
- value: "team",
321
- description: "Access to all projects in your team"
323
+ title: "I have an API key",
324
+ value: "api",
325
+ description: "Paste an API key that starts with rlm_"
322
326
  },
323
327
  {
324
328
  title: "Create free Context + Memory account",
@@ -332,10 +336,10 @@ async function gatherConfiguration(options) {
332
336
  ]
333
337
  },
334
338
  {
335
- type: (_, values) => values.profile === "runtime-only" ? null : values.apiKeyType === "project" || values.apiKeyType === "team" ? "text" : null,
339
+ type: (_, values) => values.profile === "runtime-only" ? null : values.apiKeyType === "api" ? "text" : null,
336
340
  name: "apiKey",
337
- message: (_, values) => values.apiKeyType === "team" ? "Enter your Team API key:" : "Enter your Project API key:",
338
- validate: (value) => value.startsWith("rlm_") ? true : "API key should start with rlm_"
341
+ message: (_, values) => values.apiKeyType === "api" ? "Enter your Snipara API key:" : "Enter your API key:",
342
+ validate: (value) => isManualApiKey(value) ? true : manualApiKeyValidationMessage()
339
343
  },
340
344
  {
341
345
  type: "select",
@@ -392,17 +396,17 @@ async function gatherConfiguration(options) {
392
396
  initial: options.githubPath || ""
393
397
  }
394
398
  ]);
395
- let apiKey = options.teamKey || options.apiKey;
396
- let apiKeyType = response.profile === "runtime-only" ? "none" : options.teamKey ? "team" : options.apiKey ? "project" : "none";
399
+ let apiKey = providedApiKey;
400
+ let apiKeyType = response.profile === "runtime-only" ? "none" : providedApiKey ? "api" : "none";
397
401
  let signupResult = null;
398
402
  if (!apiKey && response.profile !== "runtime-only") {
399
403
  if (response.apiKeyType === "signup") {
400
404
  signupResult = await handleSignup();
401
405
  apiKey = signupResult.apiKey;
402
- apiKeyType = "project";
403
- } else if (response.apiKeyType === "project" || response.apiKeyType === "team") {
406
+ apiKeyType = "api";
407
+ } else if (response.apiKeyType === "api") {
404
408
  apiKey = response.apiKey;
405
- apiKeyType = response.apiKeyType;
409
+ apiKeyType = "api";
406
410
  } else {
407
411
  apiKey = "YOUR_API_KEY_HERE";
408
412
  apiKeyType = "none";
@@ -430,7 +434,7 @@ async function gatherConfiguration(options) {
430
434
  {
431
435
  type: "select",
432
436
  name: "llmProvider",
433
- message: "Will you use rlm run/agent CLI too?",
437
+ message: "Will you use the Snipara Sandbox run/agent CLI too?",
434
438
  choices: [
435
439
  {
436
440
  title: "No - execute_python only",
@@ -465,14 +469,14 @@ async function gatherConfiguration(options) {
465
469
  },
466
470
  {
467
471
  type: "confirm",
468
- name: "runRlmInit",
469
- message: "Run 'rlm init' now to choose sandbox/docker/local?",
472
+ name: "runSandboxInit",
473
+ message: "Run Snipara Sandbox init now to choose sandbox/docker/local?",
470
474
  initial: false
471
475
  }
472
476
  ]);
473
477
  answers.llmProvider = runtimeResponse.llmProvider;
474
478
  answers.llmApiKey = runtimeResponse.llmApiKey;
475
- answers.runRlmInit = runtimeResponse.runRlmInit || false;
479
+ answers.runSandboxInit = runtimeResponse.runSandboxInit || false;
476
480
  }
477
481
  return answers;
478
482
  }
@@ -483,32 +487,32 @@ function resolveRequestedProfile(options) {
483
487
  if (options.profile && isInstallProfile(options.profile)) {
484
488
  return options.profile;
485
489
  }
486
- return "hosted-only";
490
+ return "hosted-companion";
487
491
  }
488
492
  function isInstallProfile(value) {
489
493
  return ["hosted-only", "hosted-companion", "full-stack", "runtime-only"].includes(value);
490
494
  }
491
495
  function installProfileChoices() {
492
496
  return [
493
- {
494
- title: "Hosted only",
495
- value: "hosted-only",
496
- description: "Default: hosted MCP config, no local companion or runtime"
497
- },
498
497
  {
499
498
  title: "Hosted + Companion",
500
499
  value: "hosted-companion",
501
- description: "Hosted MCP config plus optional local companion workflows"
500
+ description: "Default: hosted MCP config plus managed local workflow commands"
501
+ },
502
+ {
503
+ title: "Hosted only",
504
+ value: "hosted-only",
505
+ description: "Minimal setup: hosted MCP config, no local companion or sandbox"
502
506
  },
503
507
  {
504
- title: "Hosted + Companion + Runtime",
508
+ title: "Hosted + Companion + Sandbox",
505
509
  value: "full-stack",
506
- description: "Add local runtime execution as well"
510
+ description: "Add Snipara Sandbox local execution as well"
507
511
  },
508
512
  {
509
- title: "Runtime only",
513
+ title: "Sandbox only",
510
514
  value: "runtime-only",
511
- description: "Local execution only, no hosted API key required"
515
+ description: "Snipara Sandbox execution only, no hosted API key required"
512
516
  }
513
517
  ];
514
518
  }
@@ -582,8 +586,8 @@ async function handleManualSignup() {
582
586
  const response = await prompts({
583
587
  type: "text",
584
588
  name: "apiKey",
585
- message: "Paste your Project API key when ready:",
586
- validate: (value) => value.startsWith("rlm_") ? true : "API key should start with rlm_"
589
+ message: "Paste your API key when ready:",
590
+ validate: (value) => isProvisionedApiKey(value) ? true : provisionedApiKeyValidationMessage()
587
591
  });
588
592
  return { apiKey: response.apiKey };
589
593
  }
@@ -618,7 +622,10 @@ async function runDeviceAuthorization() {
618
622
  );
619
623
  if (!tokenResponse.error) {
620
624
  if (!tokenResponse.api_key) {
621
- throw new Error("Device flow completed but no project API key was returned");
625
+ throw new Error("Device flow completed but no API key was returned");
626
+ }
627
+ if (!isProvisionedApiKey(tokenResponse.api_key)) {
628
+ throw new Error("Device flow returned an API key that does not start with snp-");
622
629
  }
623
630
  spinner.succeed(
624
631
  tokenResponse.project_name ? `Authorized ${tokenResponse.project_name}` : "Authorized Snipara account"
@@ -669,6 +676,36 @@ function openBrowser(url) {
669
676
  function sleep(ms) {
670
677
  return new Promise((resolve) => setTimeout(resolve, ms));
671
678
  }
679
+ function isManualApiKey(value) {
680
+ return value.trim().startsWith("rlm_");
681
+ }
682
+ function manualApiKeyValidationMessage() {
683
+ return "API key should start with rlm_";
684
+ }
685
+ function isProvisionedApiKey(value) {
686
+ return value.trim().startsWith("snp-");
687
+ }
688
+ function provisionedApiKeyValidationMessage() {
689
+ return "New Snipara API keys should start with snp-";
690
+ }
691
+ function detectCompanionCommand() {
692
+ if (commandExists(COMPANION_COMMAND_NAME)) {
693
+ return COMPANION_COMMAND_NAME;
694
+ }
695
+ if (commandExists(LEGACY_COMPANION_COMMAND_NAME)) {
696
+ return LEGACY_COMPANION_COMMAND_NAME;
697
+ }
698
+ return null;
699
+ }
700
+ function detectSandboxCommand() {
701
+ if (commandExists(SANDBOX_COMMAND_NAME)) {
702
+ return SANDBOX_COMMAND_NAME;
703
+ }
704
+ if (commandExists(LEGACY_SANDBOX_COMMAND_NAME)) {
705
+ return LEGACY_SANDBOX_COMMAND_NAME;
706
+ }
707
+ return null;
708
+ }
672
709
  async function installPythonPackages(answers, upgrade) {
673
710
  console.log(chalk.bold(`
674
711
  \u{1F4E6} ${upgrade ? "Upgrading" : "Installing"} Python Packages
@@ -680,7 +717,7 @@ async function installPythonPackages(answers, upgrade) {
680
717
  console.log(chalk.gray(` pip install ${upgrade ? "-U " : ""}${MCP_PACKAGE_NAME}`));
681
718
  }
682
719
  if (answers.installRuntime) {
683
- console.log(chalk.gray(` pip install ${upgrade ? "-U " : ""}${RUNTIME_PACKAGE_NAME}`));
720
+ console.log(chalk.gray(` pip install ${upgrade ? "-U " : ""}${SANDBOX_PACKAGE_NAME}`));
684
721
  }
685
722
  console.log("");
686
723
  return;
@@ -690,27 +727,40 @@ async function installPythonPackages(answers, upgrade) {
690
727
  packages.push(MCP_PACKAGE_NAME);
691
728
  }
692
729
  if (answers.installRuntime) {
693
- packages.push(RUNTIME_PACKAGE_NAME);
730
+ packages.push(SANDBOX_PACKAGE_NAME);
694
731
  }
695
732
  if (packages.length === 0) return;
696
733
  const spinner = ora(
697
734
  `${upgrade ? "Upgrading" : "Installing"} ${packages.map(stripExtras).join(", ")}...`
698
735
  ).start();
699
- try {
700
- const installCmd = pipCmd === "uv" ? `uv pip install ${upgrade ? "--upgrade " : ""}${packages.join(" ")}` : `${pipCmd} install ${upgrade ? "--upgrade " : ""}${packages.join(" ")}`;
701
- execSync(installCmd, {
702
- stdio: "pipe",
703
- encoding: "utf-8"
704
- });
705
- spinner.succeed(
706
- `${upgrade ? "Upgraded" : "Installed"} ${packages.map(stripExtras).join(", ")}`
707
- );
708
- } catch {
709
- spinner.fail(`Failed to ${upgrade ? "upgrade" : "install"} Python packages`);
710
- console.log(chalk.yellow("\n Install manually with:"));
711
- console.log(chalk.gray(` pip install ${upgrade ? "--upgrade " : ""}${packages.join(" ")}
712
- `));
736
+ const attempts = [packages];
737
+ const failures = [];
738
+ for (const attemptPackages of attempts) {
739
+ try {
740
+ const installCmd = pipCmd === "uv" ? `uv pip install ${upgrade ? "--upgrade " : ""}${attemptPackages.join(" ")}` : `${pipCmd} install ${upgrade ? "--upgrade " : ""}${attemptPackages.join(" ")}`;
741
+ execSync(installCmd, {
742
+ stdio: "pipe",
743
+ encoding: "utf-8"
744
+ });
745
+ spinner.succeed(
746
+ `${upgrade ? "Upgraded" : "Installed"} ${attemptPackages.map(stripExtras).join(", ")}`
747
+ );
748
+ return;
749
+ } catch (error) {
750
+ const detail = error instanceof Error && "message" in error ? error.message.split("\n")[0] : "unknown error";
751
+ failures.push(`${attemptPackages.join(" ")}: ${detail}`);
752
+ }
713
753
  }
754
+ spinner.fail(`Failed to ${upgrade ? "upgrade" : "install"} Python packages`);
755
+ if (failures.length > 0) {
756
+ console.log(chalk.yellow("\n Attempt summary:"));
757
+ for (const failure of failures) {
758
+ console.log(chalk.gray(` - ${failure}`));
759
+ }
760
+ }
761
+ console.log(chalk.yellow("\n Install manually with:"));
762
+ console.log(chalk.gray(` pip install ${upgrade ? "--upgrade " : ""}${packages.join(" ")}
763
+ `));
714
764
  }
715
765
  function stripExtras(name) {
716
766
  return name.replace(/\[.*\]$/, "");
@@ -753,14 +803,15 @@ async function installNodeCompanion(upgrade) {
753
803
  stdio: "pipe",
754
804
  encoding: "utf-8"
755
805
  });
756
- if (commandExists("rlm-hook")) {
806
+ const installedCommand = detectCompanionCommand();
807
+ if (installedCommand) {
757
808
  spinner.succeed(
758
809
  `${upgrade ? "Upgraded" : "Installed"} ${COMPANION_PACKAGE_NAME} via ${packageManager}`
759
810
  );
760
811
  return;
761
812
  }
762
813
  failures.push(
763
- `${packageManager}: command completed but rlm-hook is still not available on PATH`
814
+ `${packageManager}: command completed but ${COMPANION_COMMAND_NAME} is still not available on PATH (legacy ${LEGACY_COMPANION_COMMAND_NAME} is also accepted)`
764
815
  );
765
816
  } catch (error) {
766
817
  const detail = error instanceof Error && "message" in error ? error.message.split("\n")[0] : "unknown error";
@@ -802,7 +853,7 @@ async function createMcpConfig(answers) {
802
853
  };
803
854
  }
804
855
  if (answers.installRuntime) {
805
- mcpConfig.mcpServers["rlm-runtime"] = {
856
+ mcpConfig.mcpServers[SANDBOX_SERVER_NAME] = {
806
857
  type: "http",
807
858
  url: "http://localhost:8765/mcp",
808
859
  headers: {}
@@ -887,22 +938,26 @@ function buildAgentsMdTemplate(answers) {
887
938
  This project uses Snipara Hosted MCP for project context and reviewed memory.
888
939
 
889
940
  - Endpoint: \`${buildHostedMcpEndpoint(answers)}\`
890
- - Auth: use \`SNIPARA_API_KEY\` or \`RLM_API_KEY\` from the environment. Never commit keys.
941
+ - Auth: use \`SNIPARA_API_KEY\` from the environment. Never commit keys.
891
942
 
892
943
  Agent task lifecycle:
893
944
 
894
- 1. Start substantial work with \`rlm_recall\` and a targeted \`rlm_context_query\`.
895
- 2. Use \`rlm_context_query\` for docs, business context, client/project truth, architecture notes, runbooks, and narrative source material.
896
- 3. When \`rlm_context_query\` returns \`answer_pack\`, treat it as the first-pass response plan: use its source facts, caveats, source map, and verification checklist before drafting claims.
897
- 4. Use \`rlm_get_chunk\` to load cited source sections returned by reference-based queries before relying on precise wording.
898
- 5. Use \`rlm_code_callers\`, \`rlm_code_imports\`, \`rlm_code_neighbors\`, or \`rlm_code_shortest_path\` for structural code questions.
899
- 6. On paid Context plans, use \`rlm_code_symbol_card\` for agent-ready symbol context and \`rlm_code_impact\` before risky multi-file changes or PR reviews.
900
- 7. Use \`rlm_plan\` or \`rlm_decompose\` only for complex work and only when the hosted server exposes them.
901
- 8. Use local file reads, \`rg\`, git commands, and test commands for exact edits, current working-tree state, and verification.
902
- 9. Use RLM Runtime only when sandboxed execution, repeatable validation, or isolated transformations materially help.
903
- 10. If a broad query is slow, retry once with a narrow keyword query before falling back to local search.
904
- 11. End substantial work with \`rlm_end_of_task_commit\` when available. Use \`rlm_remember_if_novel\` for one reusable memory while avoiding duplicates, and use \`rlm_remember\` for explicit direct memory writes.
905
- 12. Do not store secrets, tokens, passwords, private keys, raw logs, transient command output, or unreviewed guesses in memory.
945
+ 1. Start substantial work with \`snipara_recall\` and a targeted \`snipara_context_query\`.
946
+ 2. Use \`snipara_context_query\` for docs, business context, client/project truth, architecture notes, runbooks, and narrative source material.
947
+ 3. When \`snipara_context_query\` returns \`answer_pack\`, treat it as the first-pass response plan: use its source facts, caveats, source map, and verification checklist before drafting claims.
948
+ 4. Use \`snipara_get_chunk\` to load cited source sections returned by reference-based queries before relying on precise wording.
949
+ 5. Use \`snipara_code_callers\`, \`snipara_code_imports\`, \`snipara_code_neighbors\`, or \`snipara_code_shortest_path\` for structural code questions.
950
+ 6. On paid Context plans, use \`snipara_code_symbol_card\` for agent-ready symbol context and \`snipara_code_impact\` before risky multi-file changes or PR reviews.
951
+ 7. Use \`snipara_plan\` or \`snipara_decompose\` only for complex work and only when the hosted server exposes them.
952
+ 8. When the LLM has produced a visible multi-phase plan and \`snipara-companion\` is installed, run \`snipara-companion workflow start --goal "<goal>" --plan-file <plan_file>\`, then use \`workflow phase-start\`, \`workflow phase-commit\`, \`workflow resume\`, and \`final-commit\` so compaction cannot lose the next phase. Legacy \`rlm-hook\` commands remain compatible.
953
+ 9. Use local file reads, \`rg\`, git commands, and test commands for exact edits, current working-tree state, and verification.
954
+ 10. Treat every \`snipara_code_*\` response as indexed context: check its indexed commit SHA, indexing time, included file sample, coverage, freshness warnings, and sync guidance before relying on it. Legacy \`rlm_code_*\` tool IDs return the same payloads.
955
+ 11. If \`git status --short\` is dirty, warn that Snipara's indexed code graph may not include local edits; use local reads/tests for exact edits and Snipara for architecture/code graph context.
956
+ 12. Use Snipara Sandbox only when sandboxed execution, repeatable validation, or isolated transformations materially help.
957
+ 13. If a broad query is slow, retry once with a narrow keyword query before falling back to local search.
958
+ 14. End each substantial phase with \`snipara_end_of_task_commit\` or \`snipara-companion workflow phase-commit\` when companion manages the plan. End the whole managed workflow with \`snipara-companion final-commit\`.
959
+ 15. Use \`snipara_remember_if_novel\` for one reusable memory while avoiding duplicates, and use \`snipara_remember\` for explicit direct memory writes.
960
+ 16. Do not store secrets, tokens, passwords, private keys, raw logs, transient command output, or unreviewed guesses in memory.
906
961
  `;
907
962
  }
908
963
  function buildClaudeMdTemplate(answers) {
@@ -915,13 +970,17 @@ Canonical project context is in \`AGENTS.md\`. This file exists for Claude Code
915
970
  Use Snipara Hosted MCP before answering project-specific questions.
916
971
 
917
972
  - Endpoint: \`${buildHostedMcpEndpoint(answers)}\`
918
- - Start substantial work with \`rlm_recall\` and a targeted \`rlm_context_query\`.
919
- - Use \`rlm_context_query\` for source truth and \`rlm_get_chunk\` for exact cited sections.
920
- - When \`rlm_context_query\` returns \`answer_pack\`, use its facts, caveats, source map, and verification checklist before drafting claims.
921
- - Use \`rlm_code_callers\`, \`rlm_code_imports\`, \`rlm_code_neighbors\`, or \`rlm_code_shortest_path\` for structural code questions.
922
- - On paid Context plans, use \`rlm_code_symbol_card\` before editing important symbols and \`rlm_code_impact\` before risky multi-file changes or PR reviews.
923
- - Use RLM Runtime only when sandboxed execution or repeatable validation materially helps.
924
- - End substantial work with \`rlm_end_of_task_commit\` when available; use \`rlm_remember_if_novel\` or \`rlm_remember\` only for narrow durable memories.
973
+ - Start substantial work with \`snipara_recall\` and a targeted \`snipara_context_query\`.
974
+ - Use \`snipara_context_query\` for source truth and \`snipara_get_chunk\` for exact cited sections.
975
+ - When \`snipara_context_query\` returns \`answer_pack\`, use its facts, caveats, source map, and verification checklist before drafting claims.
976
+ - Use \`snipara_code_callers\`, \`snipara_code_imports\`, \`snipara_code_neighbors\`, or \`snipara_code_shortest_path\` for structural code questions.
977
+ - On paid Context plans, use \`snipara_code_symbol_card\` before editing important symbols and \`snipara_code_impact\` before risky multi-file changes or PR reviews.
978
+ - Check every \`snipara_code_*\` response for indexed commit SHA, indexing time, included files, coverage, and freshness warnings. Legacy \`rlm_code_*\` IDs return the same payloads.
979
+ - Use local file reads, \`rg\`, \`git status --short\`, and tests for exact edits/current working tree; use Snipara for architecture and indexed code graph context.
980
+ - When the plan is visible and \`snipara-companion\` is installed, use \`snipara-companion workflow start\`, \`phase-start\`, \`phase-commit\`, \`workflow resume\`, and \`final-commit\` to keep phase state durable across compaction. Legacy \`rlm-hook\` commands remain compatible.
981
+ - Use Snipara Sandbox only when sandboxed execution or repeatable validation materially helps.
982
+ - End substantial work with \`snipara_end_of_task_commit\` when available; for managed workflows, end every phase with \`snipara-companion workflow phase-commit\` and the task with \`snipara-companion final-commit\`.
983
+ - Use \`snipara_remember_if_novel\` or \`snipara_remember\` only for narrow durable memories.
925
984
  - Do not store secrets, one-off command output, raw logs, or unreviewed guesses in memory.
926
985
  - Use the Snipara Claude Code plugin only when slash commands, skills, or hooks are helpful; Hosted MCP remains the normal agent path.
927
986
  `;
@@ -938,16 +997,18 @@ This workspace uses Snipara Hosted MCP for current project context, business/cli
938
997
 
939
998
  - Check the configured Snipara MCP server before answering project-specific questions.
940
999
  - Endpoint: \`${buildHostedMcpEndpoint(answers)}\`
941
- - Use \`rlm_recall\` for durable decisions, preferences, and validated learnings.
942
- - Use \`rlm_context_query\` for docs, business context, current client/project truth, and narrative source material.
943
- - When \`rlm_context_query\` returns \`answer_pack\`, use its facts, caveats, source map, and verification checklist before drafting claims.
944
- - Use \`rlm_get_chunk\` before relying on exact cited wording from reference-based results.
945
- - Use \`rlm_code_callers\`, \`rlm_code_imports\`, \`rlm_code_neighbors\`, or \`rlm_code_shortest_path\` for structural code questions.
946
- - On paid Context plans, use \`rlm_code_symbol_card\` before editing important symbols and \`rlm_code_impact\` before risky multi-file changes or PR reviews.
947
- - Use \`rlm_plan\` or \`rlm_decompose\` only for complex work and only when available.
948
- - Use local file reads and tests for exact code edits and current working-tree state.
949
- - Use RLM Runtime only when sandboxed execution or repeatable validation materially helps.
950
- - End substantial work with \`rlm_end_of_task_commit\` when available; use \`rlm_remember_if_novel\` or \`rlm_remember\` only for narrow durable memories. Never store secrets.
1000
+ - Use \`snipara_recall\` for durable decisions, preferences, and validated learnings.
1001
+ - Use \`snipara_context_query\` for docs, business context, current client/project truth, and narrative source material.
1002
+ - When \`snipara_context_query\` returns \`answer_pack\`, use its facts, caveats, source map, and verification checklist before drafting claims.
1003
+ - Use \`snipara_get_chunk\` before relying on exact cited wording from reference-based results.
1004
+ - Use \`snipara_code_callers\`, \`snipara_code_imports\`, \`snipara_code_neighbors\`, or \`snipara_code_shortest_path\` for structural code questions.
1005
+ - On paid Context plans, use \`snipara_code_symbol_card\` before editing important symbols and \`snipara_code_impact\` before risky multi-file changes or PR reviews.
1006
+ - Check every \`snipara_code_*\` response for indexed commit SHA, indexing time, included files, coverage, and freshness warnings. Legacy \`rlm_code_*\` IDs return the same payloads.
1007
+ - Use \`snipara_plan\` or \`snipara_decompose\` only for complex work and only when available.
1008
+ - Use local file reads, \`rg\`, \`git status --short\`, and tests for exact code edits and current working-tree state.
1009
+ - When \`snipara-companion\` is installed and the LLM has a visible multi-phase plan, use \`snipara-companion workflow start\`, \`phase-start\`, \`phase-commit\`, \`workflow resume\`, and \`final-commit\` so the next phase survives compaction. Legacy \`rlm-hook\` commands remain compatible.
1010
+ - Use Snipara Sandbox only when sandboxed execution or repeatable validation materially helps.
1011
+ - End substantial work with \`snipara_end_of_task_commit\` when available; for managed workflows, end every phase with \`snipara-companion workflow phase-commit\` and the task with \`snipara-companion final-commit\`. Use \`snipara_remember_if_novel\` or \`snipara_remember\` only for narrow durable memories. Never store secrets.
951
1012
  `;
952
1013
  }
953
1014
  function buildCodexConfigTemplate(answers) {
@@ -1012,8 +1073,8 @@ async function createClaudeDesktopConfig(answers) {
1012
1073
  }
1013
1074
  };
1014
1075
  if (answers.installRuntime) {
1015
- config.mcpServers["rlm-runtime"] = {
1016
- command: "rlm",
1076
+ config.mcpServers[SANDBOX_SERVER_NAME] = {
1077
+ command: detectSandboxCommand() || SANDBOX_COMMAND_NAME,
1017
1078
  args: ["mcp-serve"],
1018
1079
  env: {
1019
1080
  SNIPARA_API_KEY: answers.apiKey,
@@ -1107,8 +1168,19 @@ set -euo pipefail
1107
1168
  export SNIPARA_PROJECT_SLUG="${answers.projectSlug}"
1108
1169
  ${answers.projectId ? `export SNIPARA_PROJECT_ID="${answers.projectId}"` : ""}
1109
1170
 
1110
- if command -v rlm-hook >/dev/null 2>&1; then
1111
- rlm-hook session-bootstrap || true
1171
+ SNIPARA_COMPANION_BIN=""
1172
+ if command -v ${COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1173
+ SNIPARA_COMPANION_BIN="${COMPANION_COMMAND_NAME}"
1174
+ elif command -v ${LEGACY_COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1175
+ SNIPARA_COMPANION_BIN="${LEGACY_COMPANION_COMMAND_NAME}"
1176
+ fi
1177
+
1178
+ if [ -n "$SNIPARA_COMPANION_BIN" ]; then
1179
+ if [ -f ".snipara/workflow/current.json" ]; then
1180
+ "$SNIPARA_COMPANION_BIN" workflow resume --include-session-context || true
1181
+ else
1182
+ "$SNIPARA_COMPANION_BIN" session-bootstrap || true
1183
+ fi
1112
1184
  fi
1113
1185
  `;
1114
1186
  }
@@ -1119,8 +1191,15 @@ set -euo pipefail
1119
1191
  export SNIPARA_PROJECT_SLUG="${answers.projectSlug}"
1120
1192
  ${answers.projectId ? `export SNIPARA_PROJECT_ID="${answers.projectId}"` : ""}
1121
1193
 
1122
- if command -v rlm-hook >/dev/null 2>&1; then
1123
- rlm-hook emit-event --event-type tool_result --json '{"source":"claude-code-hook"}' || true
1194
+ SNIPARA_COMPANION_BIN=""
1195
+ if command -v ${COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1196
+ SNIPARA_COMPANION_BIN="${COMPANION_COMMAND_NAME}"
1197
+ elif command -v ${LEGACY_COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1198
+ SNIPARA_COMPANION_BIN="${LEGACY_COMPANION_COMMAND_NAME}"
1199
+ fi
1200
+
1201
+ if [ -n "$SNIPARA_COMPANION_BIN" ]; then
1202
+ "$SNIPARA_COMPANION_BIN" emit-event --event-type tool_result --json '{"source":"claude-code-hook"}' || true
1124
1203
  fi
1125
1204
  `;
1126
1205
  }
@@ -1131,8 +1210,19 @@ set -euo pipefail
1131
1210
  export SNIPARA_PROJECT_SLUG="${answers.projectSlug}"
1132
1211
  ${answers.projectId ? `export SNIPARA_PROJECT_ID="${answers.projectId}"` : ""}
1133
1212
 
1134
- if command -v rlm-hook >/dev/null 2>&1; then
1135
- rlm-hook task-commit --summary "Claude Code compacted local session context" --outcome partial || true
1213
+ SNIPARA_COMPANION_BIN=""
1214
+ if command -v ${COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1215
+ SNIPARA_COMPANION_BIN="${COMPANION_COMMAND_NAME}"
1216
+ elif command -v ${LEGACY_COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1217
+ SNIPARA_COMPANION_BIN="${LEGACY_COMPANION_COMMAND_NAME}"
1218
+ fi
1219
+
1220
+ if [ -n "$SNIPARA_COMPANION_BIN" ]; then
1221
+ if [ -f ".snipara/workflow/current.json" ]; then
1222
+ "$SNIPARA_COMPANION_BIN" task-commit --summary "Claude Code compacted while a managed workflow state existed. Resume with snipara-companion workflow resume --include-session-context and continue from .snipara/workflow/current.json." --category workflow-compaction --outcome partial || true
1223
+ else
1224
+ "$SNIPARA_COMPANION_BIN" task-commit --summary "Claude Code compacted local session context" --outcome partial || true
1225
+ fi
1136
1226
  fi
1137
1227
  `;
1138
1228
  }
@@ -1154,7 +1244,7 @@ ${answers.projectId ? `SNIPARA_PROJECT_ID=${answers.projectId}` : ""}
1154
1244
  const llmVarName = answers.llmProvider === "openai" ? "OPENAI_API_KEY" : "ANTHROPIC_API_KEY";
1155
1245
  envVars += `
1156
1246
 
1157
- # RLM-Runtime LLM Provider (for rlm run/agent CLI)
1247
+ # Snipara Sandbox LLM Provider (for snipara-sandbox run/agent CLI)
1158
1248
  ${llmVarName}=${answers.llmApiKey}`;
1159
1249
  }
1160
1250
  envVars = envVars.trim();
@@ -1195,7 +1285,7 @@ ${envVars}
1195
1285
  function getClientGuidance(client) {
1196
1286
  if (client === "claude-code") {
1197
1287
  return [
1198
- "Claude Code can use both the hosted MCP surface and the local rlm-hook companion flows.",
1288
+ "Claude Code can use both the hosted MCP surface and the local snipara-companion flows.",
1199
1289
  "If hooks are enabled, the edge layer forwards lifecycle signals without owning durable memory locally."
1200
1290
  ];
1201
1291
  }
@@ -1230,30 +1320,30 @@ function getClientGuidance(client) {
1230
1320
  }
1231
1321
  function getCompanionCommands(answers) {
1232
1322
  const projectIdFlag = answers.projectId ? ` --project-id ${answers.projectId}` : "";
1233
- const apiKeyFlag = answers.apiKeyType === "none" || answers.apiKey.includes("YOUR_") ? " --api-key <rlm_key>" : ` --api-key ${answers.apiKey}`;
1323
+ const apiKeyFlag = answers.apiKeyType === "none" || answers.apiKey.includes("YOUR_") ? " --api-key <rlm-key>" : ` --api-key ${answers.apiKey}`;
1234
1324
  const clientFlag = getCompanionInitClientFlag(answers.aiClient);
1235
1325
  const businessOnboardingCommands = answers.installCompanion ? [
1236
1326
  {
1237
1327
  title: "Preview a business folder import",
1238
- command: "rlm-hook onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json",
1328
+ command: `${COMPANION_COMMAND_NAME} onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json`,
1239
1329
  purpose: "Classify a local or LLM-materialized business folder and review the Snipara sync manifest before upload."
1240
1330
  },
1241
1331
  {
1242
1332
  title: "Apply a business folder import",
1243
- command: "rlm-hook onboard-folder ./client-export --source-provider local_folder --apply",
1333
+ command: `${COMPANION_COMMAND_NAME} onboard-folder ./client-export --source-provider local_folder --apply`,
1244
1334
  purpose: "Upload approved business-context documents to hosted Snipara and trigger document reindexing."
1245
1335
  }
1246
1336
  ] : [
1247
1337
  {
1248
1338
  title: "Enable business folder onboarding",
1249
1339
  command: "npx create-snipara repair --with-companion",
1250
- purpose: "Install snipara-companion so this project can run rlm-hook onboard-folder without using the dashboard."
1340
+ purpose: `Install ${COMPANION_PACKAGE_NAME} so this project can run ${COMPANION_COMMAND_NAME} onboard-folder without using the dashboard.`
1251
1341
  }
1252
1342
  ];
1253
1343
  return [
1254
1344
  {
1255
1345
  title: "Bootstrap local companion",
1256
- command: `rlm-hook init${clientFlag}${projectIdFlag}${apiKeyFlag}`,
1346
+ command: `${COMPANION_COMMAND_NAME} init${clientFlag}${projectIdFlag}${apiKeyFlag}`,
1257
1347
  purpose: "Write local companion config for this workstation."
1258
1348
  },
1259
1349
  {
@@ -1268,44 +1358,69 @@ function getCompanionCommands(answers) {
1268
1358
  },
1269
1359
  {
1270
1360
  title: "Run a focused hosted query",
1271
- command: 'rlm-hook query --query "how does auth middleware work?" --max-tokens 4000',
1361
+ command: `${COMPANION_COMMAND_NAME} query --query "how does auth middleware work?" --max-tokens 4000`,
1272
1362
  purpose: "Pull ranked source context before editing, reviewing, or drafting."
1273
1363
  },
1274
1364
  {
1275
1365
  title: "Load linked standards only when needed",
1276
- command: "rlm-hook shared-context --categories MANDATORY BEST_PRACTICES",
1366
+ command: `${COMPANION_COMMAND_NAME} shared-context --categories MANDATORY BEST_PRACTICES`,
1277
1367
  purpose: "Fetch project-linked team or workspace guidance without treating it as memory."
1278
1368
  },
1279
1369
  {
1280
1370
  title: "Generate a hosted plan",
1281
- command: 'rlm-hook plan --query "Implement webhook retry hardening" --max-tokens 3000',
1371
+ command: `${COMPANION_COMMAND_NAME} plan --query "Implement webhook retry hardening" --max-tokens 3000`,
1282
1372
  purpose: "Produce a structured execution plan against indexed project knowledge."
1283
1373
  },
1374
+ {
1375
+ title: "Start a managed workflow from the visible plan",
1376
+ command: `${COMPANION_COMMAND_NAME} workflow start --goal "Implement webhook retry hardening" --plan-file ./plan.md`,
1377
+ purpose: "Record the LLM-visible plan in .snipara/workflow/current.json so phase state survives compaction."
1378
+ },
1379
+ {
1380
+ title: "Start the current workflow phase",
1381
+ command: `${COMPANION_COMMAND_NAME} workflow phase-start context`,
1382
+ purpose: "Mark a phase active and print the required Snipara context gate for the agent."
1383
+ },
1384
+ {
1385
+ title: "Analyze code impact before a risky change",
1386
+ command: `${COMPANION_COMMAND_NAME} code impact --changed-files src/api/webhooks.ts tests/webhooks.test.ts --diff-summary "webhook retry hardening"`,
1387
+ purpose: "Use paid Context code impact analysis to surface likely tests, docs, routes, config, and risks."
1388
+ },
1284
1389
  {
1285
1390
  title: "Upload or refresh a doc",
1286
- command: "rlm-hook upload --path docs/local-playbook.md --file ./docs/local-playbook.md",
1391
+ command: `${COMPANION_COMMAND_NAME} upload --path docs/local-playbook.md --file ./docs/local-playbook.md`,
1287
1392
  purpose: "Push local notes or docs into hosted Snipara context."
1288
1393
  },
1289
1394
  ...businessOnboardingCommands,
1290
1395
  {
1291
1396
  title: "Inspect a specific chunk",
1292
- command: "rlm-hook chunk get --chunk-id <chunk_id>",
1397
+ command: `${COMPANION_COMMAND_NAME} chunk get --chunk-id <chunk_id>`,
1293
1398
  purpose: "Open an exact chunk returned by references-based search."
1294
1399
  },
1295
1400
  {
1296
1401
  title: "Bootstrap the session memory view",
1297
- command: "rlm-hook session-bootstrap",
1402
+ command: `${COMPANION_COMMAND_NAME} session-bootstrap`,
1298
1403
  purpose: "Load durable decisions, learnings, and optional short-lived carryover at session start."
1299
1404
  },
1300
1405
  {
1301
1406
  title: "Ask memory about past decisions",
1302
- command: 'rlm-hook recall --query "What did we decide about auth retries?" --type decision',
1407
+ command: `${COMPANION_COMMAND_NAME} recall --query "What did we decide about auth retries?" --type decision`,
1303
1408
  purpose: "Query durable memory for past decisions, preferences, or validated learnings."
1304
1409
  },
1305
1410
  {
1306
1411
  title: "Commit durable task memory",
1307
- command: 'rlm-hook task-commit --summary "Hardened webhook retries and updated tests" --category engineering --outcome completed --files src/api/webhooks.ts tests/webhooks.test.ts',
1412
+ command: `${COMPANION_COMMAND_NAME} task-commit --summary "Hardened webhook retries and updated tests" --category engineering --outcome completed --files src/api/webhooks.ts tests/webhooks.test.ts`,
1308
1413
  purpose: "Persist reusable outcomes back into hosted memory after the work is done."
1414
+ },
1415
+ {
1416
+ title: "Commit a managed workflow phase",
1417
+ command: `${COMPANION_COMMAND_NAME} workflow phase-commit context --summary "Loaded context and mapped impacted files" --files src/api/webhooks.ts tests/webhooks.test.ts`,
1418
+ purpose: "Persist this phase through hosted memory and advance the local managed workflow state."
1419
+ },
1420
+ {
1421
+ title: "Commit the final managed workflow result",
1422
+ command: `${COMPANION_COMMAND_NAME} final-commit --summary "Shipped webhook retry hardening and tests" --files src/api/webhooks.ts tests/webhooks.test.ts`,
1423
+ purpose: "Persist the final workflow outcome and close the managed workflow after verification."
1309
1424
  }
1310
1425
  ];
1311
1426
  }
@@ -1318,7 +1433,7 @@ async function createCompanionPack(answers) {
1318
1433
  fs.mkdirSync(packDir, { recursive: true });
1319
1434
  const readme = `# Snipara Companion Pack
1320
1435
 
1321
- This project uses Snipara as a hosted-first context and memory layer with an optional local companion CLI.
1436
+ This project uses Snipara as a hosted-first context and memory layer with local companion workflow helpers.
1322
1437
 
1323
1438
  ## Install Profile
1324
1439
 
@@ -1329,7 +1444,7 @@ This project uses Snipara as a hosted-first context and memory layer with an opt
1329
1444
  - Installed local companion: \`${answers.installCompanion ? "yes" : "no"}\`
1330
1445
  - Generated hosted MCP config: \`${answers.profile !== "runtime-only" ? "yes" : "no"}\`
1331
1446
  - Installed local snipara-mcp package: \`${answers.installMcp ? "yes" : "no"}\`
1332
- - Installed runtime: \`${answers.installRuntime ? "yes" : "no"}\`
1447
+ - Installed Snipara Sandbox: \`${answers.installRuntime ? "yes" : "no"}\`
1333
1448
  - Generated hooks: \`${answers.installHooks ? "yes" : "no"}\`
1334
1449
 
1335
1450
  ## Local Detection Snapshot
@@ -1338,7 +1453,7 @@ This project uses Snipara as a hosted-first context and memory layer with an opt
1338
1453
  - .mcp.json present: \`${detection.files.mcpConfig ? "yes" : "no"}\`
1339
1454
  - .env.local present: \`${detection.files.envLocal ? "yes" : "no"}\`
1340
1455
  - Companion CLI on PATH: \`${detection.tooling.companionCli ? "yes" : "no"}\`
1341
- - Runtime CLI on PATH: \`${detection.tooling.runtimeCli ? "yes" : "no"}\`
1456
+ - Snipara Sandbox CLI on PATH: \`${detection.tooling.runtimeCli ? "yes" : "no"}\`
1342
1457
 
1343
1458
  ## Client Guidance
1344
1459
 
@@ -1350,11 +1465,11 @@ Use this when Claude, ChatGPT, Codex, or another LLM client has already material
1350
1465
 
1351
1466
  ${answers.installCompanion ? `Preview first:
1352
1467
 
1353
- \`rlm-hook onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json\`
1468
+ \`${COMPANION_COMMAND_NAME} onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json\`
1354
1469
 
1355
1470
  Apply only after reviewing the manifest:
1356
1471
 
1357
- \`rlm-hook onboard-folder ./client-export --source-provider local_folder --apply\`` : `This setup did not install snipara-companion. Enable it before business folder imports:
1472
+ \`${COMPANION_COMMAND_NAME} onboard-folder ./client-export --source-provider local_folder --apply\`` : `This setup did not install snipara-companion. Enable it before business folder imports:
1358
1473
 
1359
1474
  \`npx create-snipara repair --with-companion\``}
1360
1475
 
@@ -1384,6 +1499,7 @@ ${item.purpose}`
1384
1499
 
1385
1500
  - Context first: use hosted queries, shared-context, and document loads for source truth.
1386
1501
  - Memory second: use session bootstrap and task commit for durable decisions, learnings, and preferences.
1502
+ - Managed workflow when a visible plan exists: \`workflow start\`, \`phase-start\`, \`phase-commit\`, \`workflow resume\`, and \`final-commit\` keep phase state durable across compaction.
1387
1503
  - Durable memory, policy, and orchestration stay hosted in Snipara.
1388
1504
  - The local companion is optional tooling for capture, bootstrap, upload, exploration, doctor, repair, and explicit task summaries.
1389
1505
  `;
@@ -1405,30 +1521,36 @@ ${item.purpose}`
1405
1521
  console.log(chalk.green(" \u2713 Created .snipara/companion/README.md"));
1406
1522
  console.log(chalk.green(" \u2713 Created .snipara/companion/commands.json"));
1407
1523
  }
1408
- async function runRlmInit() {
1409
- console.log(chalk.bold("\n\u{1F527} Running RLM-Runtime Configuration\n"));
1524
+ async function runSandboxInit() {
1525
+ const sandboxCommand = detectSandboxCommand() || SANDBOX_COMMAND_NAME;
1526
+ console.log(chalk.bold("\n\u{1F527} Running Snipara Sandbox Configuration\n"));
1410
1527
  console.log(
1411
- chalk.dim(" Starting 'rlm init' - follow the prompts to configure execution environment...\n")
1528
+ chalk.dim(
1529
+ ` Starting '${sandboxCommand} init' - follow the prompts to configure execution environment...
1530
+ `
1531
+ )
1412
1532
  );
1413
1533
  return new Promise((resolve) => {
1414
- const child = spawn("rlm", ["init"], {
1534
+ const child = spawn(sandboxCommand, ["init"], {
1415
1535
  stdio: "inherit",
1416
1536
  shell: true
1417
1537
  });
1418
1538
  child.on("close", (code) => {
1419
1539
  if (code === 0) {
1420
- console.log(chalk.green("\n \u2713 RLM-Runtime configured successfully"));
1540
+ console.log(chalk.green("\n \u2713 Snipara Sandbox configured successfully"));
1421
1541
  } else if (code !== null) {
1422
1542
  console.log(chalk.yellow(`
1423
- \u26A0\uFE0F rlm init exited with code ${code}`));
1424
- console.log(chalk.dim(" You can run 'rlm init' manually later."));
1543
+ \u26A0\uFE0F ${sandboxCommand} init exited with code ${code}`));
1544
+ console.log(chalk.dim(` You can run '${sandboxCommand} init' manually later.`));
1425
1545
  }
1426
1546
  resolve();
1427
1547
  });
1428
1548
  child.on("error", (error) => {
1429
1549
  console.log(chalk.yellow(`
1430
- \u26A0\uFE0F Could not run rlm init: ${error.message}`));
1431
- console.log(chalk.dim(" Run 'rlm init' manually after installation completes."));
1550
+ \u26A0\uFE0F Could not run ${sandboxCommand} init: ${error.message}`));
1551
+ console.log(
1552
+ chalk.dim(` Run '${SANDBOX_COMMAND_NAME} init' manually after installation completes.`)
1553
+ );
1432
1554
  resolve();
1433
1555
  });
1434
1556
  });
@@ -1483,9 +1605,9 @@ async function runValidation(answers, includeHostedCheck) {
1483
1605
  detail: answers.installCompanion && !detection.tooling.companionCli ? `${COMPANION_PACKAGE_NAME} not found on PATH` : "Companion CLI ready or not requested"
1484
1606
  });
1485
1607
  checks.push({
1486
- name: "runtime_cli",
1608
+ name: "sandbox_cli",
1487
1609
  status: answers.installRuntime ? detection.tooling.runtimeCli ? "pass" : "warn" : "pass",
1488
- detail: answers.installRuntime && !detection.tooling.runtimeCli ? "rlm CLI not found on PATH" : "Runtime CLI ready or not requested"
1610
+ detail: answers.installRuntime && !detection.tooling.runtimeCli ? `${SANDBOX_COMMAND_NAME} CLI not found on PATH` : "Snipara Sandbox CLI ready or not requested"
1489
1611
  });
1490
1612
  checks.push({
1491
1613
  name: "companion_pack",
@@ -1581,14 +1703,14 @@ async function testHostedConnection(answers) {
1581
1703
  }
1582
1704
  ];
1583
1705
  const settingsResponse = await callHostedMcp(answers, "tools/call", {
1584
- name: "rlm_settings",
1706
+ name: "snipara_settings",
1585
1707
  arguments: {}
1586
1708
  });
1587
1709
  if (settingsResponse.ok && !settingsResponse.data.error) {
1588
1710
  checks.push({
1589
1711
  name: "hosted_settings",
1590
1712
  status: "pass",
1591
- detail: "rlm_settings tool call succeeded"
1713
+ detail: "snipara_settings tool call succeeded"
1592
1714
  });
1593
1715
  } else {
1594
1716
  checks.push({
@@ -1640,7 +1762,7 @@ async function callHostedMcp(answers, method, params) {
1640
1762
  function describeHostedHttpFailure(status, bodyText) {
1641
1763
  const detail = bodyText.trim().slice(0, 120);
1642
1764
  if (status === 401 || status === 403) {
1643
- return `Auth failed (${status}). Check the project/team API key and project slug.`;
1765
+ return `Auth failed (${status}). Check the API key and project slug.`;
1644
1766
  }
1645
1767
  if (status === 404) {
1646
1768
  return "Endpoint or project slug was not found. Check the hosted MCP URL.";
@@ -1679,7 +1801,9 @@ function printSuccess(answers, report) {
1679
1801
  );
1680
1802
  }
1681
1803
  if (answers.installRuntime) {
1682
- console.log(chalk.green(" \u2713 rlm-runtime") + chalk.dim(" - Safe code execution"));
1804
+ console.log(
1805
+ chalk.green(` \u2713 ${stripExtras(SANDBOX_PACKAGE_NAME)}`) + chalk.dim(" - Safe code execution")
1806
+ );
1683
1807
  }
1684
1808
  if (answers.installCompanion) {
1685
1809
  console.log(
@@ -1710,20 +1834,27 @@ function printSuccess(answers, report) {
1710
1834
  printNextStep("Open .snipara/companion/README.md for local commands and repair flow.");
1711
1835
  printNextStep("Run create-snipara doctor anytime you want a fresh local validation report.");
1712
1836
  if (answers.installCompanion) {
1713
- printNextStep("Use rlm-hook query / plan / upload / task-commit for explicit local workflows.");
1714
1837
  printNextStep(
1715
- "For business folders, preview with: rlm-hook onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json"
1838
+ `${COMPANION_COMMAND_NAME} is the primary companion command; legacy ${LEGACY_COMPANION_COMMAND_NAME} remains compatible.`
1716
1839
  );
1717
1840
  printNextStep(
1718
- "Apply after review with: rlm-hook onboard-folder ./client-export --source-provider local_folder --apply"
1841
+ `Use ${COMPANION_COMMAND_NAME} query / plan / upload / task-commit for explicit local workflows.`
1842
+ );
1843
+ printNextStep(
1844
+ `For business folders, preview with: ${COMPANION_COMMAND_NAME} onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json`
1845
+ );
1846
+ printNextStep(
1847
+ `Apply after review with: ${COMPANION_COMMAND_NAME} onboard-folder ./client-export --source-provider local_folder --apply`
1719
1848
  );
1720
1849
  } else if (answers.profile !== "runtime-only") {
1721
1850
  printNextStep(
1722
1851
  "For dashboardless business folder imports, enable companion with: npx create-snipara repair --with-companion"
1723
1852
  );
1724
1853
  }
1725
- if (answers.installRuntime && !answers.runRlmInit) {
1726
- printNextStep("Run rlm init when you want to choose sandbox/docker/local execution.");
1854
+ if (answers.installRuntime && !answers.runSandboxInit) {
1855
+ printNextStep(
1856
+ `Run ${SANDBOX_COMMAND_NAME} init when you want to choose sandbox/docker/local execution.`
1857
+ );
1727
1858
  }
1728
1859
  if (answers.githubRepo) {
1729
1860
  printNextStep(
@@ -1749,11 +1880,11 @@ function printSuccess(answers, report) {
1749
1880
  }
1750
1881
  function commandExists(command) {
1751
1882
  try {
1752
- execSync(`${command} --version`, { stdio: "ignore", shell: "/bin/sh" });
1883
+ execSync(`${command} --version`, { stdio: "ignore", shell: "/bin/sh", timeout: 2500 });
1753
1884
  return true;
1754
1885
  } catch {
1755
1886
  try {
1756
- execSync(`command -v ${command}`, { stdio: "ignore", shell: "/bin/sh" });
1887
+ execSync(`command -v ${command}`, { stdio: "ignore", shell: "/bin/sh", timeout: 1e3 });
1757
1888
  return true;
1758
1889
  } catch {
1759
1890
  return false;
@@ -1790,8 +1921,8 @@ function detectEnvironment() {
1790
1921
  uv: commandExists("uv"),
1791
1922
  docker: commandExists("docker"),
1792
1923
  git: commandExists("git"),
1793
- companionCli: commandExists("rlm-hook"),
1794
- runtimeCli: commandExists("rlm")
1924
+ companionCli: Boolean(detectCompanionCommand()),
1925
+ runtimeCli: Boolean(detectSandboxCommand())
1795
1926
  },
1796
1927
  existingConfig: {
1797
1928
  slug: existingConfig?.slug,
@@ -1804,8 +1935,13 @@ function detectEnvironment() {
1804
1935
  function loadExistingAnswers(options) {
1805
1936
  const detection = detectEnvironment();
1806
1937
  const effectiveProfile = resolveMaintenanceProfile(detection, options.profile);
1807
- const apiKey = options.teamKey || options.apiKey || readApiKeyFromEnvFiles() || "YOUR_API_KEY_HERE";
1808
- const apiKeyType = options.teamKey ? "team" : options.apiKey || readApiKeyFromEnvFiles() ? "project" : effectiveProfile === "runtime-only" ? "none" : "none";
1938
+ const providedApiKey = options.apiKey?.trim();
1939
+ if (providedApiKey && !isManualApiKey(providedApiKey)) {
1940
+ throw new Error(manualApiKeyValidationMessage());
1941
+ }
1942
+ const envApiKey = readApiKeyFromEnvFiles();
1943
+ const apiKey = providedApiKey || envApiKey || "YOUR_API_KEY_HERE";
1944
+ const apiKeyType = effectiveProfile === "runtime-only" ? "none" : providedApiKey || envApiKey ? "api" : "none";
1809
1945
  return buildAnswersFromProfile({
1810
1946
  projectSlug: options.slug || detection.existingConfig.slug || detection.projectSlug || "my-project",
1811
1947
  projectId: options.projectId || detection.existingConfig.projectId || "",
@@ -1832,7 +1968,7 @@ function resolveMaintenanceProfile(detection, explicitProfile) {
1832
1968
  if (detection.existingConfig.hasSniparaServer) {
1833
1969
  return "hosted-only";
1834
1970
  }
1835
- return "hosted-only";
1971
+ return "hosted-companion";
1836
1972
  }
1837
1973
  function readApiKeyFromEnvFiles() {
1838
1974
  const candidates = [".env.local", ".env"];
@@ -1952,7 +2088,7 @@ function getExistingConfig() {
1952
2088
  try {
1953
2089
  const config = JSON.parse(fs.readFileSync(mcpConfigPath, "utf-8"));
1954
2090
  const sniparaServer = config.mcpServers?.snipara;
1955
- const runtimeServer = config.mcpServers?.["rlm-runtime"];
2091
+ const runtimeServer = config.mcpServers?.[SANDBOX_SERVER_NAME] || config.mcpServers?.[LEGACY_RUNTIME_SERVER_NAME];
1956
2092
  const match = sniparaServer?.url?.match(/\/mcp\/([^/]+)$/);
1957
2093
  return {
1958
2094
  slug: match?.[1],
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "create-snipara",
3
- "version": "1.3.9",
4
- "description": "Onboard Snipara Hosted MCP Context + Memory with auth plus optional local helper and runtime workflows",
3
+ "version": "1.3.12",
4
+ "description": "Onboard Snipara Hosted MCP Context + Memory with auth, companion workflows, and optional Snipara Sandbox",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
7
7
  "bin": {
@@ -21,7 +21,7 @@
21
21
  "snipara",
22
22
  "create-snipara",
23
23
  "mcp",
24
- "rlm-runtime",
24
+ "snipara-sandbox",
25
25
  "context-optimization",
26
26
  "llm",
27
27
  "ai-agents",