Skip to content

SB-062: st push command — push branches and sync stack state to backend #99

@dugshub

Description

@dugshub

SB-062: st push command — push branches and sync stack state to backend

Epic: EP-010 (Remote-First Stack Management)
Complexity: M (Medium)
Depends on: #103 (SB-066 — Stack sync API endpoint)


Goal

Add st push to the stack CLI that pushes git branches to GitHub and syncs stack metadata to the Stack Bench backend API. After st push, the backend has everything it needs to render the UI — no local repo path required.

Current State

The StackProvider protocol already defines push() at:

  • app/backend/src/molecules/providers/stack_provider.py:51-53async def push(self, stack_name: str, *, branch_positions: list[int] | None = None) -> StackResult
  • app/backend/src/molecules/providers/stack_cli_adapter.py:75-85StackCLIAdapter.push() wraps stack submit (pushes + creates PRs)

The stack CLI state file (~/.claude/stacks/stack-bench.json) already tracks per-branch: name, tip (SHA), pr (number), and parentTip. This is exactly the payload the backend needs.

Flow

st push
  ├─ 1. git push origin <branch> (for each branch in stack)
  ├─ 2. Read stack state from ~/.claude/stacks/<repo>.json
  ├─ 3. POST /api/v1/stacks/{id}/sync with branch SHAs
  │     (creates branches/PRs in DB if they don't exist)
  └─ 4. Print sync results (SHAs updated, PRs linked)

Implementation Steps

  1. Stack CLI (st push command) — Add a push subcommand that:

    • Iterates stack branches and runs git push origin <branch> for each
    • Reads updated SHAs from git after push
    • Calls the backend sync endpoint (POST /api/v1/stacks/{id}/sync)
    • Falls back gracefully if backend is unreachable (push still succeeds)
  2. Backend sync endpoint — See SB-066: Stack sync API endpoint — update branch SHAs and PR state from GitHub #103. The push command is the primary consumer.

  3. StackCLIAdapter update — Update app/backend/src/molecules/providers/stack_cli_adapter.py to distinguish push (git push only) from submit (push + create PRs).

API Contract (consumed by st push)

POST /api/v1/stacks/{stack_id}/sync

Request:
{
  "branches": [
    {
      "name": "dugshub/my-stack/1-feature",
      "position": 1,
      "head_sha": "abc123...",
      "pr_number": 42,
      "pr_url": "https://github.com/owner/repo/pull/42"
    }
  ]
}

Response:
{
  "stack": { ... },
  "branches": [ ... ],
  "synced_count": 3,
  "created_count": 1
}

Key Files

File Role
app/backend/src/molecules/providers/stack_provider.py StackProvider protocol — push() method
app/backend/src/molecules/providers/stack_cli_adapter.py CLI adapter — current push wraps stack submit
~/.claude/stacks/stack-bench.json Stack CLI state — branch names, SHAs, PR numbers
app/backend/src/organisms/api/routers/stacks.py Router — needs sync endpoint
app/backend/src/molecules/apis/stack_api.py API facade — needs sync method

Dependencies

Acceptance Criteria

  • st push pushes all stack branches to origin via git push
  • st push calls backend sync endpoint after successful push
  • Branch SHAs in DB match remote HEAD after push
  • PR numbers/URLs are linked in DB if PRs exist on GitHub
  • Push succeeds even if backend is unreachable (graceful degradation)
  • st push --branch 2 pushes only branch at position 2
  • Integration test covers push → sync → DB state verification

Metadata

Metadata

Assignees

No one assigned

    Labels

    epic:EP-010EP-010: Remote-First Stack ManagementinfrastructureInfrastructure and architecture

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions