---
name: okstra-container-build
description: |
  Use to bring up, inspect, or tear down the okstra user-test container runtime for an implementation task — the docker-compose group okstra deploys from a task's worktree so a human can poke at the running build. Trigger words include "okstra container", "okstra container up", "okstra container down", "bring up the container", "spin up the container", "tear down the container", "container status", "user-test environment", "user test environment", "docker compose up please", "spin up this task in a container".
---

# OKSTRA Container Build

Single entry point for the okstra user-test container runtime. okstra provisions a docker-compose group from an `implementation` task's worktree (the `docker-compose.yml` at the worktree root), and labels it with the task's run-trace so later sub-commands can find the group. This skill drives that lifecycle. Sub-commands:

| Sub-command | What it does |
|---|---|
| `up` | Integrate the task's stages into the worktree, run `docker compose up -d`, and poll healthchecks. |
| `status` | Query the running containers for a task-key (by run-trace label). |
| `down` | Tear down the containers (label query); `--all` covers every container group in the project. |

## Step 0: Preflight (shared)

Before any sub-command:

<!-- BEGIN FRAGMENT: bash-invocation-rule -->
Run one Bash tool call, starting with the literal token `okstra` (never wrapped in `if`/`eval`/`export`/`$(...)`/`VAR=...`/`||`/`&&`/`npx` — a non-literal leading token defeats the `Bash(okstra:*)` permission match):
<!-- END FRAGMENT: bash-invocation-rule -->

```bash
okstra preflight --runtime claude-code
```

On `Okstra preflight: ready`, carry the fixed `Project root` line and pass it as `--project-root <projectRoot>` to every `okstra container` call below. On `Okstra preflight: failed`, show `Reason` and `Recovery`, then stop.

<!-- BEGIN FRAGMENT: preflight-outdated-cli -->
If the call fails with `unknown command: preflight`, the `okstra` binary on PATH predates this skill — tell the user to update it (`npm i -g okstra@latest`), then stop (`/okstra-setup` does not update the binary).
<!-- END FRAGMENT: preflight-outdated-cli -->

Docker itself must be installed and running for `up`/`status`/`down` to work. If a sub-command fails with a docker connection error, tell the user to start Docker (Desktop / daemon) and retry — do not try to start docker yourself.

<!-- BEGIN FRAGMENT: python-bootstrap-note -->
Every subsequent `okstra <subcmd>` call self-bootstraps its Python path, so this skill never needs `okstra paths --shell` / `export PYTHONPATH=...`.
<!-- END FRAGMENT: python-bootstrap-note -->

## Step 1: Dispatch by intent

Classify the user's request into one sub-command using the sub-command table above.

- Clear verbs route directly: "bring up/deploy/up" → `up`; "status" → `status`; "tear down/down" → `down`.
- If the request is ambiguous (e.g. "take a look at the okstra container"), present a numbered picker. Recommend the 1–2 most likely facets first, and make the **last option always "Enter directly"** so the user can name any facet:

  ```
  What would you like to do?
  1. status — check the running containers (recommended)
  2. up — bring up this task's containers
  3. Enter directly (one of up / status / down)
  ```

  The full facet list is the `Sub-command | What it does` table above — never hide a facet; if the user picks "Enter directly", let them name any row.

When the user chains multiple facets in one message (e.g. "bring it up, then show me the status"), execute them sequentially — Step 0 runs once, each sub-command section runs once.

Every sub-command needs a **task-key** (`<project-id>:<task-group>:<task-id>`) — the container group is bound to one implementation task's worktree. Resolve it the same way across sub-commands:

1. If the user gave a full task-key, use it.
2. If the user gave only a task-id, run `okstra model-io task-selection-input --project-root <projectRoot> --task-ref <task-id>`. Use the fixed `Selection status`, `Task key`, and numbered `Candidate` lines: one match → use its task key; multiple → list candidates and ask (3-option picker); none → report not found.
3. `down --all` is the only call that does not need a task-key (see `down`).

---

## up

Brings up the task's container group: integrates the implementation stages into the task worktree, synthesizes the compose env override, runs `docker compose up -d`, and polls healthchecks.

**Preconditions** (state them if unmet, do not guess):
- The task must be an `implementation` task whose worktree is registered in `~/.okstra/worktrees/registry.json`. If `up` fails with "task worktree is not in the registry" → the task has no implementation worktree yet; tell the user to run the `implementation` phase first.
- The worktree root must contain a `docker-compose.yml`. If `up` fails with "there is no ... at the worktree root" → no compose file shipped with this task; surface the message verbatim.
- Every stage declared in the approved plan's Stage Map must be `done`. `up` integrates the whole task, so a partially-finished task (e.g. only stage 1 of 3 done) is refused rather than deployed as if complete (gate in `stage_targets.py`, shared with whole-task `final-verification`). If `up` fails with `final-verification(whole-task): stage N not done — run implementation --stage N first`, surface that message verbatim and tell the user to finish the named stage via the `implementation` phase with `--stage N`.

Run:

```bash
okstra container up --project-root <projectRoot> --task-key <task-key> --text
```

Read the fixed output fields and report the provisioned services. If a service failed its healthcheck, the call surfaces the failing services and the `docker compose ... logs` line to inspect — relay that line; do not invent your own.

After a successful `up`, run the `status --text` command below and read its numbered container `ports` fields to tell the user how to reach the running build. Also explain that `okstra container status <task-key>` / `okstra container down <task-key>` manage it from here. For *what to verify* once it is up, point the user to the implementation report's §5.7.9 Manual User Test (Draft) — its steps and expected results are the manual test script for this build.

---

## status

Reports the running containers, queried by the run-trace label — the source of truth for "is it up".

```bash
okstra container status --project-root <projectRoot> --task-key <task-key> --text
```

Read the fixed `Project name` and numbered `Container` fields and report:

| Field | Meaning |
|---|---|
| `projectName` | the compose project name (label group) |
| `containers` | running containers found by label — empty array means nothing is up |

If `containers` is empty, say the group is not running and offer `up`.

To follow a service's live logs, the user runs `docker compose -p <projectName> logs -f <service>` (get `<projectName>` from `status`).

---

## down

Tears down the container group — removes the containers found by the run-trace label.

Single task:

```bash
okstra container down --project-root <projectRoot> --task-key <task-key> --text
```

Every container group in the project (no task-key needed):

```bash
okstra container down --project-root <projectRoot> --all --text
```

Read the fixed `Downed` fields and report each torn-down project name. `down` runs `docker compose -p <name> down --remove-orphans` — a compose-native teardown that removes the project's containers and the compose network, but deliberately keeps named volumes (e.g. DB data) by NOT passing `-v`. Confirm with the user before running `--all`, since it takes down every okstra container group in the project at once. A single-task `down` is safe to run directly once the task-key is resolved.

---

## Output Rules (shared)

- Responses should be concise and written in Korean unless the user requests otherwise.
- The fixed text fields from each `okstra container` call are the source of truth — do not run raw `docker` commands to second-guess them unless the CLI fails and the user explicitly asks for a manual fallback.
- Show the resolved `<task-key>` in the heading so the user can confirm disambiguation.
- Surface failure messages from the CLI verbatim (compose-up failures, missing worktree/compose file) — do not paraphrase the remediation line.
- Display container/service states as-is from the fixed fields; do not normalize or remap.
