Skip to content

feat(cli): honest non-interactive init — fail on skew, no false success (rc.2 M4)#687

Open
coderdan wants to merge 1 commit into
mainfrom
feat/honest-noninteractive-init
Open

feat(cli): honest non-interactive init — fail on skew, no false success (rc.2 M4)#687
coderdan wants to merge 1 commit into
mainfrom
feat/honest-noninteractive-init

Conversation

@coderdan

@coderdan coderdan commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Problem (rc.2 M4)

Non-interactive stash init reported success for setups that hadn't fully completed — so CI/agents couldn't trust its exit code or its summary. Three honesty gaps:

  1. Version skew was warn-and-proceed. A non-interactive run can't reconcile a behind skew (an installed @cipherstash/* older than this CLI expects) — it won't mutate an install without consent — so it warned and kept going, scaffolding config/client against mismatched packages, then printed "Setup complete".
  2. "Setup complete" was unconditional. Even when EQL install failed (eqlInstalled=false), the header still said complete — and "✓ Database connection verified" was printed although init only resolves a URL, never connects.
  3. "Skills loaded" was unconditional. The Claude/Codex handoff launch prompt pointed the agent at the skills dir even when installSkills() copied nothing (stripped build) — telling it to read files that aren't there.

Fix

  1. Fail on skew. Non-interactive + behind skew → refuse with a non-zero exit (CliExit(1)) and the exact align command, instead of proceeding. The npm dist-tags deliver broken/stale packages: adapters' latest=0.0.0, stack latest=0.19.0; stash init installs unpinned #661/fix(cli): pin init's installs to the release's own package versions (#661) #666 no-mutation principle is preserved (execSync still never called — only the post-warning action changes). ahead skew stays a warn (install likely fine; update the CLI). Interactive runs still offer to align.
  2. Honest summary. When EQL is required but missing (!eqlInstalled && integration !== 'prisma-next'), the summary reads "Setup incomplete" and init exits non-zero, pointing at stash eql install. "Database connection verified" → "Database URL resolved"; "Encryption client scaffolded" shows only when a client was actually written (skipped for Prisma Next).
  3. Honest skills prose. The launch-prompt skills clause is conditional on installSkills() returning something.

Scope notes

Verification

  • Updated install-deps skew tests (refuses + exit 1, still never mutates); new init-command honest-summary tests (EQL-missing → exit 1 + "Setup incomplete"; prisma-next eqlInstalled=false → completes).
  • Suite: 542 unit / 62 e2e green, code:check clean. Changeset: stash minor. Skill (stash-cli) + doc comments updated.
  • No new e2e: a full non-interactive init needs live auth + a DB (which is why there's no init e2e); the honest-summary and skew-fail logic is unit-covered.

https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w

Summary by CodeRabbit

  • Bug Fixes

    • stash init now exits with an error when required dependencies have incompatible versions and provides an alignment command.
    • Setup reports accurately reflect whether the encryption client, EQL extension, and other components were installed.
    • Missing EQL installation now clearly reports “Setup incomplete” and directs users to install it.
    • Claude and Codex handoff messages no longer reference skills that were not installed.
  • Documentation

    • Updated stash init guidance for dependency version mismatches and incomplete EQL setup.

…ss (rc.2 M4)

Non-interactive `stash init` reported success for setups that didn't fully
complete. Three honesty gaps closed:

1. Version skew. A non-interactive run can't reconcile a `behind` skew (it
   won't mutate an install without consent), so instead of warning-and-
   proceeding — scaffolding against packages older than this CLI expects and
   then claiming success — it now REFUSES with a non-zero exit (CliExit(1))
   and the exact align command. The #661/#666 no-mutation principle is
   preserved (execSync still not called); only the post-warning action
   changes from proceed to fail. `ahead` skew stays a warn (install likely
   fine; update the CLI).

2. False 'Setup complete'. The summary header and the auth/db/scaffold
   checkmarks were unconditional. Now: when EQL is required but not installed
   (eqlInstalled=false AND integration !== prisma-next), the summary reads
   'Setup incomplete' and init exits non-zero, pointing at `stash eql install`.
   'Database connection verified' → 'Database URL resolved' (init resolves a
   URL, never opens a connection). 'Encryption client scaffolded' is shown
   only when a client was written (clientFilePath set; skipped for prisma-next).

3. False 'skills loaded'. The Claude/Codex handoff launch prompt referenced
   the skills dir unconditionally; a stripped build installs no skills, so it
   told the agent to read files that aren't there. The clause is now
   conditional on installSkills() actually copying something.

Tests: install-deps skew tests updated to assert the refusal (still never
mutates); new init-command honest-summary tests (EQL-missing → exit 1 +
'Setup incomplete'; prisma-next eqlInstalled=false → completes). Skill + doc
comments updated. Suite 542 unit / 62 e2e green, code:check clean. Changeset:
stash minor.

Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
@coderdan
coderdan requested a review from a team as a code owner July 17, 2026 08:57
@changeset-bot

changeset-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 27520d6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 11 packages
Name Type
stash Minor
@cipherstash/basic-example Patch
@cipherstash/e2e Patch
@cipherstash/stack Minor
@cipherstash/stack-drizzle Minor
@cipherstash/stack-supabase Minor
@cipherstash/prisma-next Minor
@cipherstash/wizard Minor
@cipherstash/bench Patch
@cipherstash/test-kit Patch
@cipherstash/prisma-next-example Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

stash init now exits non-zero for non-interactive dependency skew and incomplete EQL setup, reports completion from actual state, preserves Prisma Next’s exception, and avoids mentioning absent agent skills in Claude and Codex handoff prompts.

Changes

Init outcome handling

Layer / File(s) Summary
Dependency skew refusal
packages/cli/src/messages.ts, packages/cli/src/commands/init/steps/install-deps.ts, packages/cli/src/commands/init/steps/__tests__/install-deps.test.ts
Non-interactive dependency skew now prints alignment commands, logs the skew message, rejects with CliExit, and avoids installation commands.
Init completion validation
packages/cli/src/commands/init/index.ts, packages/cli/src/commands/init/__tests__/init-command.test.ts, .changeset/honest-noninteractive-init.md, skills/stash-cli/SKILL.md
Completion checkmarks reflect actual state; missing EQL reports incomplete setup and exits non-zero except for Prisma Next.
Conditional agent handoff prompts
packages/cli/src/commands/impl/steps/handoff-claude.ts, packages/cli/src/commands/impl/steps/handoff-codex.ts
Skills-directory instructions are included only when skills were installed.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant initCommand
  participant installDepsStep
  participant installEqlStep
  participant AgentHandoff
  User->>initCommand: run stash init
  initCommand->>installDepsStep: install dependencies
  installDepsStep-->>initCommand: dependency state or CliExit
  initCommand->>installEqlStep: install EQL extension
  installEqlStep-->>initCommand: eqlInstalled state
  initCommand->>AgentHandoff: build prompt from installed skills
Loading

Possibly related PRs

Suggested reviewers: calvinbrewer

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main CLI change: non-interactive init now fails on skew and avoids false success.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/honest-noninteractive-init

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli/src/commands/impl/steps/handoff-claude.ts`:
- Around line 41-48: Make all generated handoff guidance respect the
installed-skills state: in handoff-claude.ts, update the setup prompt loaded by
the launchPrompt flow so the empty-skills variant does not reference skill
directories or the unwritten AGENTS.md file, while retaining valid skill
guidance when skills exist; in handoff-codex.ts, update its generated guidance
so .codex/skills/ is omitted when installed.length is zero.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f8da61ce-6475-4788-b2d3-6295b53bb730

📥 Commits

Reviewing files that changed from the base of the PR and between f188c7a and 27520d6.

📒 Files selected for processing (9)
  • .changeset/honest-noninteractive-init.md
  • packages/cli/src/commands/impl/steps/handoff-claude.ts
  • packages/cli/src/commands/impl/steps/handoff-codex.ts
  • packages/cli/src/commands/init/__tests__/init-command.test.ts
  • packages/cli/src/commands/init/index.ts
  • packages/cli/src/commands/init/steps/__tests__/install-deps.test.ts
  • packages/cli/src/commands/init/steps/install-deps.ts
  • packages/cli/src/messages.ts
  • skills/stash-cli/SKILL.md

Comment on lines +41 to +48
const skillsClause =
installed.length > 0
? `The installed skills under ${CLAUDE_SKILLS_DIR}/ have the rules; `
: ''
const launchPrompt =
mode === 'plan'
? `Read ${SETUP_PROMPT_REL_PATH} and produce the planning deliverable it describes. The installed skills under ${CLAUDE_SKILLS_DIR}/ have the rules; ${CONTEXT_REL_PATH} has the project facts. Do not edit code or run mutating commands during this phase.`
: `Read ${SETUP_PROMPT_REL_PATH} and complete the setup steps. The installed skills under ${CLAUDE_SKILLS_DIR}/ have the rules; ${CONTEXT_REL_PATH} has the project facts.`
? `Read ${SETUP_PROMPT_REL_PATH} and produce the planning deliverable it describes. ${skillsClause}${CONTEXT_REL_PATH} has the project facts. Do not edit code or run mutating commands during this phase.`
: `Read ${SETUP_PROMPT_REL_PATH} and complete the setup steps. ${skillsClause}${CONTEXT_REL_PATH} has the project facts.`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make all generated handoff guidance honor the installed-skills state.

The launch prompts now conditionally omit skill-directory references, but the setup prompt they always load still references those directories when no skills were installed.

  • packages/cli/src/commands/impl/steps/handoff-claude.ts#L41-L48: make the empty-skills setup prompt valid for Claude; it currently also references an AGENTS.md file this handoff does not write.
  • packages/cli/src/commands/impl/steps/handoff-codex.ts#L60-L67: omit .codex/skills/ from generated guidance when installed.length === 0.
📍 Affects 2 files
  • packages/cli/src/commands/impl/steps/handoff-claude.ts#L41-L48 (this comment)
  • packages/cli/src/commands/impl/steps/handoff-codex.ts#L60-L67
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/commands/impl/steps/handoff-claude.ts` around lines 41 - 48,
Make all generated handoff guidance respect the installed-skills state: in
handoff-claude.ts, update the setup prompt loaded by the launchPrompt flow so
the empty-skills variant does not reference skill directories or the unwritten
AGENTS.md file, while retaining valid skill guidance when skills exist; in
handoff-codex.ts, update its generated guidance so .codex/skills/ is omitted
when installed.length is zero.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant