Skip to content

Ship a first-run trust loop: openspine init (#118) - #269

Merged
George-RD merged 1 commit into
mainfrom
George-RD/dev-118
Aug 21, 2026
Merged

Ship a first-run trust loop: openspine init (#118)#269
George-RD merged 1 commit into
mainfrom
George-RD/dev-118

Conversation

@George-RD

@George-RD George-RD commented Aug 21, 2026

Copy link
Copy Markdown
Owner

What

Adds openspine init --owner <telegram_user_id> [--name <display>]: a single, non-interactive command that turns a built binary into a running, governed install, replacing the repository-setup ceremony as the documented first-run path.

The command establishes the trust ceremony end to end:

  1. Seed key — writes the configuration + owner-only openspine.env (artifact/grant/webhook keys, mode 0600).
  2. Approval anchor — binds the single trusted owner principal into a fresh kernel store, via the same identity::bootstrap_owner_principal the kernel uses at boot.
  3. Test — prints a readiness report and a plain-language trust ceremony with honest next steps (provider login, Telegram, Gmail).

Also: extracts shared non-interactive key-material helpers (cli/bootstrap.rs) reused by the interactive openspine setup wizard; adds the owner Telegram id to StarterConfig; documents the ceremony in docs/first-run.md; leads the README and site quickstart with openspine init.

Why

The value-equation audit found setup effort and time-to-first-value were the weakest variables. The old public path asked users to clone, build, copy an example YAML, and hand-edit a Telegram id before seeing the product. This collapses local first-run into one command while keeping every kernel trust boundary intact — no new ungated path, deterministic pipeline unchanged, and the principal init writes is exactly the one boot would create.

Design decision (raised by review)

--owner is the Telegram user id (the authoritative trusted-principal binding), not just a display name. A display-name-only init would bind the StarterConfig placeholder (telegram_user_id: 1) as the authoritative owner on first boot; bootstrap_owner_principal is fail-closed, so a later real id would trap the user with an unbootable install. Requiring the real id up front removes that trap. init also only writes the principal on a demonstrably fresh data root, so it never appends a bootstrap audit against a store the kernel has not yet validated.

Testing

  • ./scripts/check.sh — green (fmt, clippy, full suite, 45/45 openspec specs, claims register).
  • Unit: config/key writing captures the owner + seed keys; fresh install requires --owner; conflicting --owner on an existing install is rejected.
  • E2E smoke (tests/first_run_smoke.rs): spawns the binary in a clean temp dir and asserts the loop completes — config, 0600 seed keys, owner principal (kernel.db), and ceremony report.

Scope note

The #118 issue body also sketches a maximalist onboarding vision (preflight engine, Gmail thread picker, boundary/receipt DTOs) from a superseded auto-generated plan ("Restructured into the cohesive roadmap"). A real Lyra draft needs a live provider + Docker + Telegram + Gmail and cannot run in the specified clean-temp-dir smoke; those rungs are surfaced truthfully as next steps, matching the ticket's "distinguish required configuration, optional capability, and current alpha limits."

Implementation notes (summary)

  • Deviation: --owner = Telegram user id (+ --name), to avoid binding the telegram_user_id: 1 placeholder as the authoritative fail-closed owner.
  • Deviation: init bootstraps the principal only on a fresh data root, preserving run()'s validate-before-bootstrap ordering (main.rs 300-317).
  • Deviation: did not build the deprecated maximalist plan; reached the hermetic trust anchor and surfaced external rungs as next steps.
  • Edge cases: StarterConfig::to_config() hardcoded the placeholder owner id; bootstrap_owner_principal is idempotent + fail-closed on config mismatch.
  • Question for review: is --owner = Telegram user id acceptable vs. a display name?

Closes #118


Summary by cubic

Introduces openspine init: a single command that turns a built binary into a running, governed install. This replaces the repo-setup ceremony to cut first-run friction while preserving the kernel’s trust boundaries and deterministic boot.

  • Old behavior: clone/build/copy YAML/edit owner id or run openspine setup. New behavior: openspine init --owner <telegram_user_id> [--name] writes config and seed keys, bootstraps the owner on a fresh data root, then prints readiness and the trust ceremony. Interactive openspine setup remains available.
  • Owner binding is immutable. init requires a real --owner on fresh installs and rejects a conflicting id on existing installs. It only bootstraps the owner when no encrypted state exists; otherwise the kernel performs the validated bootstrap on next start.
  • Key material is safe by default. init writes openspine.env at mode 0600, never overwrites existing entries, and refuses to mint a new OPENSPINE_ARTIFACT_KEY over populated state to avoid orphaning the vault.
  • Extracts shared non-interactive bootstrap helpers (cli/bootstrap.rs) and reuses them in the wizard. Adds the owner Telegram id to StarterConfig. No ungated authority path is introduced; it uses the same identity::bootstrap_owner_principal as boot.

Rollout and migration

  • Fresh installs: run openspine init --owner <telegram_user_id> [--name] [--config <path>]. This is now the documented first-run path.
  • Existing installs: you can run openspine init to fill missing keys; it will not rebind the owner. Keep your existing openspine.env if the data dir holds encrypted state; a new artifact key will be refused.
  • Docs lead with openspine init (README, site quickstart, docs/first-run.md). Tests cover config/key writing, owner-id guard, and an end-to-end smoke of the trust loop.

Written for commit e1692bb. Summary will update on new commits.

Review in cubic

…#118)

Replace the repository-setup ceremony with one non-interactive command that
establishes the trust loop: seed key -> approval anchor -> test.

- Add `openspine init --owner <telegram_user_id> [--name <display>]`: writes
  the configuration and owner-only seed key file, binds the single trusted
  owner principal (fresh data root only, via the same
  identity::bootstrap_owner_principal the kernel uses at boot), runs readiness,
  and prints a plain-language trust ceremony with honest next steps.
- Require the real owner id up front and reject a conflicting id on an existing
  install: the owner binding is immutable and the kernel fails closed on a
  mismatch, so a placeholder would trap the owner.
- Extract shared, non-interactive key-material helpers (cli/bootstrap.rs) reused
  by the interactive `openspine setup` wizard; add owner Telegram id to
  StarterConfig.
- Document the trust ceremony in docs/first-run.md; lead README and the site
  quickstart with `openspine init`.
- Tests: unit coverage for the config/key writing and owner-immutability guard;
  an end-to-end smoke that spawns the binary in a clean temp dir and asserts the
  loop completes (config, 0600 seed keys, owner principal, ceremony report).

Kernel trust boundaries are untouched: no new ungated path, the deterministic
pipeline is unchanged, and the principal init writes is exactly the one boot
would create.

Closes #118
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@George-RD, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 3 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6e76d003-1363-4f91-88bd-3429244afca5

📥 Commits

Reviewing files that changed from the base of the PR and between 1bde90b and e1692bb.

📒 Files selected for processing (13)
  • README.md
  • crates/openspine-kernel/src/cli/bootstrap.rs
  • crates/openspine-kernel/src/cli/init.rs
  • crates/openspine-kernel/src/cli/init_tests.rs
  • crates/openspine-kernel/src/cli/mod.rs
  • crates/openspine-kernel/src/cli/starter.rs
  • crates/openspine-kernel/src/cli/wizard.rs
  • crates/openspine-kernel/src/cli/wizard/tests.rs
  • crates/openspine-kernel/src/env_file.rs
  • crates/openspine-kernel/src/main.rs
  • crates/openspine-kernel/tests/first_run_smoke.rs
  • docs/first-run.md
  • site/src/content/docs/quickstart.md

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.

@George-RD
George-RD merged commit 733dc5d into main Aug 21, 2026
4 checks passed
@George-RD
George-RD deleted the George-RD/dev-118 branch August 21, 2026 09:16
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.

Ship a first-run trust loop instead of a repository setup exercise

1 participant