Skip to content

Add local mode: pull, plan, apply without a server deployment#22

Draft
aparajon wants to merge 2 commits intomainfrom
armand/local-mode
Draft

Add local mode: pull, plan, apply without a server deployment#22
aparajon wants to merge 2 commits intomainfrom
armand/local-mode

Conversation

@aparajon
Copy link
Copy Markdown
Collaborator

@aparajon aparajon commented Apr 18, 2026

Adds zero-infrastructure local mode — the full plan/apply lifecycle works with just the binary and a MySQL connection. No server deployment, no Docker, no AWS needed.

How it works: When no --endpoint or --profile is configured and the database is in ~/.schemabot/config.yaml's local section, the CLI auto-starts a background schemabot serve daemon. Storage lives on the developer's local MySQL (localhost:3306/_schemabot), fully decoupled from the target database which can be anywhere (local, remote, PlanetScale).

New commands:

  • schemabot pull --dsn <dsn> -e <env> — bootstraps a declarative schema directory from a live database
  • schemabot local status/stop/reset — manage the background server

Quickstart:

schemabot pull --dsn "root@tcp(localhost:3306)/mydb" -e staging -o ./schema
# edit a .sql file
schemabot plan -s ./schema -e staging
schemabot apply -s ./schema -e staging

Architecture:

  • Background daemon (schemabot serve) auto-starts on first command, persists between commands
  • Storage on localhost:3306/_schemabot (auto-bootstrapped via EnsureSchema)
  • Target and storage fully decoupled — supports PlanetScale and managed MySQL where CREATE DATABASE is restricted
  • Orphan process detection: stale processes killed on startup, schemabot local stop finds processes by port if PID file is missing
  • ~/.schemabot/config.yaml extended with local section for database connection config (supports env: secret refs)

Copilot AI review requested due to automatic review settings April 18, 2026 19:18
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds “zero-infrastructure” CLI workflows by introducing a schema bootstrap command (schemabot pull) and enabling schemabot plan to run directly against a target DB in-process (local plan mode) when schemabot.yaml contains a DSN.

Changes:

  • Add schemabot pull to extract live MySQL schema into per-table .sql files plus a generated schemabot.yaml.
  • Add local plan mode to schemabot plan using an in-process LocalClient backed by an in-memory storage implementation.
  • Add integration tests covering the pull + local-plan workflow.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
pkg/storage/memstore/memstore.go New in-memory storage.Storage implementation for local plan mode.
pkg/cmd/main.go Registers the new pull CLI command.
pkg/cmd/commands/pull.go Implements schemabot pull (schema extraction + file generation).
pkg/cmd/commands/plan.go Adds local plan execution path using LocalClient + memstore.
pkg/cmd/commands/common.go Extends schemabot.yaml config with dsn for local mode.
integration/pull_plan_integration_test.go Integration tests for pull + local plan behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/cmd/commands/pull.go Outdated
Comment thread pkg/cmd/commands/pull.go
Comment thread pkg/cmd/commands/pull.go Outdated
Comment thread pkg/cmd/commands/plan.go Outdated
Comment thread pkg/storage/memstore/memstore.go Outdated
Comment thread integration/pull_plan_integration_test.go
Comment thread integration/pull_plan_integration_test.go Outdated
@aparajon aparajon force-pushed the armand/local-mode branch 2 times, most recently from 09ecfc7 to 2fb883b Compare April 18, 2026 23:54
@aparajon aparajon changed the title Add pull command and stateless local plan mode Add local mode: pull, plan, apply without a server deployment Apr 19, 2026
@aparajon aparajon force-pushed the armand/local-mode branch 24 times, most recently from 470da36 to 6606bfe Compare April 19, 2026 04:40
@aparajon aparajon force-pushed the armand/local-mode branch 2 times, most recently from fc9a871 to 89b053b Compare April 20, 2026 18:39
Introduces a local mode that lets users run schema changes against any
MySQL database without deploying the SchemaBot server. A background
daemon process starts automatically and uses the target database itself
for storage, eliminating external dependencies.

Key additions:
- `schemabot pull` command to fetch current schemas from a database
- `schemabot local` subcommand for daemon lifecycle management
- Local MySQL detection via reserved 'local' profile
- Background daemon with orphan process management
- Integration tests for local mode and daemon lifecycle
- Configuration docs covering profiles, local databases, and server setup

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 11 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/local/server.go
Comment thread pkg/cmd/commands/local.go
Comment thread README.md Outdated
Comment on lines +138 to +142
// Local mode: explicit --profile local, or database found in local config
if activeProfile == LocalProfile || (endpoint == "" && profile == "" && len(database) > 0 && database[0] != "") {
db := ""
if len(database) > 0 {
db = database[0]
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

The local-mode condition (endpoint=="" && profile=="" && database provided) runs before resolving the configured default profile. This means if a user has default_profile: staging with a remote endpoint, but also has that database in ~/.schemabot/config.yaml under local, the CLI will still prefer local mode and ignore the default remote profile. To match the UX described, consider attempting local mode only when endpoint resolution (including default profile) yields an empty endpoint, or when the active profile is explicitly local.

Copilot uses AI. Check for mistakes.
Comment thread pkg/cmd/commands/common.go
Comment thread pkg/cmd/commands/common.go
Comment thread pkg/local/server.go
Comment thread pkg/cmd/commands/common.go Outdated
Comment thread pkg/cmd/commands/common.go
Comment thread pkg/local/server.go Outdated
- Use mysql.ParseDSN in stripDatabaseFromDSN for unix socket safety
- Restrict findProcessOnPort to LISTEN state, handle multi-line lsof output
- Derive checkLocalMySQL error messages from configured DSN, not hard-coded addr
- Add RedactedStorageDSN for local status display
- Check SCHEMABOT_PROFILE env var in resolveEndpoint for local mode detection
- Return config load errors from tryLocalMode instead of swallowing
- Track selected database name when database param is empty
- Fix go install path in README (pkg/cmd, not module root)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

2 participants