---
name: okstra-setup
description: One-time bootstrap for okstra in a new project or on a new machine — installs the okstra runtime via npx and creates the project's .okstra/project.json. Trigger words include "okstra setup", "setup okstra", "initialize okstra", "okstra init", "first time okstra setup", "configure okstra here".
---

# okstra-setup

One-time bootstrap. Run when okstra is being used for the first time on this
machine, or when adopting okstra in a new project.

## When to use

- `~/.okstra/version` is missing or stale → okstra runtime is not installed yet.
- The current project has no `.okstra/project.json` yet.
- The user says "set up okstra here", "first time", "okstra init", etc.

## When NOT to use

- A task is already in flight → use [`okstra-run`](../okstra-run/SKILL.md) or
  [`okstra-inspect status`](../okstra-inspect/SKILL.md).
- Day-to-day usage in a project that already has `project.json` — skip this skill.

## Prerequisites

Inform the user up-front and confirm before continuing:

- **Node 18+** required (runs `npx`). If missing, point to `brew install node`
  or `nvm`.
- **Python 3.10+** required (runs the okstra core).
- The current working directory must be inside the project that will host the
  okstra metadata. If unsure, ask with `AskUserQuestion` for an absolute project
  root before proceeding.

## Step 1: Install okstra

Resolve `<host-runtime>` from the launcher's `OKSTRA_RUNTIME_HOST` when present;
otherwise use the registered host ID declared by the current harness. Use the
existing host registry and its aliases rather than maintaining a provider-to-host
lookup in this skill. Claude Code, Codex, Grok, Antigravity, and Kimi are examples,
not a closed list; additional registered hosts follow the same rule.

Do not infer the host from model names, worker providers, installed executables,
or `PATH`. A GLM model running inside another harness uses that harness's host
identity; a separately registered GLM harness uses its own registered identity.
If neither the launcher nor the harness identifies the host, use `auto` to let
the existing registry resolve session evidence. Report an unresolved or rejected
identity without substituting Claude Code or claiming host setup is verified.
When `auto` resolves successfully, carry the reported resolved host ID forward
as the literal `<host-runtime>` value instead of detecting again at each step.

Replace `<host-runtime>` with the resolved literal value before executing each
command. Keep the same resolved host for installation, preflight, diagnostics,
and retries, including retries against another project or npm cache directory.
The runtime registry validates host IDs; the skill command contract is checked
by `tests/contract/test_docs_runtime_contract.py::test_skills_declare_their_host_runtime_explicitly`.

```bash
npx -y okstra@latest install --runtime <host-runtime>
```

This single command populates everything the user needs:

- `~/.okstra/{lib/python, bin, version}` — python + bash runtime
- Host skill targets selected by the installer, including the shared Agent skill
  home — installed targets are recorded in `~/.okstra/installed-skills.json`
- `~/.okstra/installed-skills.json` — manifest for safe uninstall

The skill should run this even if `~/.okstra/version` already exists —
`install` is idempotent (per-file hash skip), so re-running is cheap and
ensures the install matches the package version currently on disk.

Show the final summary line back to the user (`version stamp: x.y.z`).

If install fails, surface the stderr verbatim. Do NOT try to "fix" it by
running the legacy `okstra-install.sh` — that path is dev-only.

For npm `EPERM` / `EACCES` errors under its cache directory, distinguish package
preparation from okstra installation. npm's root-owned-files message is not
evidence of root ownership. Inspect ownership and the session's write restrictions
before proposing a permission change. Retry with a temporary cache directory
writable by the current session, substituting its literal absolute path:

```bash
npx --cache <writable-cache-directory> -y okstra@latest install --runtime <host-runtime>
```

Do not run recursive `sudo chown` based only on npm's generic message. A cache
override does not grant network access or permission to write the installation
targets; follow the host's permission mechanism if either remains blocked.

**Bash invocation rule (permission-friendly)**: after Step 1, every Bash command in this skill MUST begin with the literal token `okstra` and pass literal argument values. Do not introduce shell variables (`$PROJECT_ROOT`, `$PROJECT_ID`, ...), `$(...)` command substitution, leading `VAR=...` assignments, or wrap commands in `if`/`eval`/`||`/`&&` — any of those make the leading token non-literal, defeat the `Bash(okstra:*)` permission match, and force a confirmation prompt on every call. When a prior tool call emitted a path or value, paste the literal string into the next command. Every `okstra <subcmd>` call self-bootstraps its Python path — never run `okstra paths --shell` / `export PYTHONPATH=...`.

## Step 2: Resolve PROJECT_ROOT

```bash
okstra preflight --runtime <host-runtime>
```

Read the fixed `Okstra preflight`, `Project root`, `Project JSON`, `Project ID`,
`Reason`, and `Recovery` lines.

- `Ok: true` → carry `Project root` as a literal absolute string and paste it into every subsequent command in this skill.
- `Ok: false`, `Stage: resolve` → ask the user (`AskUserQuestion`, free text) for an absolute project root and rerun as a separate Bash tool call with the literal absolute path:

  ```bash
  okstra preflight --runtime <host-runtime> --cwd /abs/path/from/user
  ```

- `Ok: false`, `Stage: project_json_missing` → proceed to Step 3 (this is the normal create path).
- `Ok: false`, any other `Stage` (`python`, `parse`, `project_json_invalid`) → show the fixed `Reason` line to the user verbatim and follow the `Recovery` line (typically `okstra doctor --runtime <host-runtime>` to diagnose, then `okstra ensure-installed --runtime <host-runtime>` or re-running the Step 1 install). `Reason` is the SSOT — do not hand-enumerate stage causes.

## Step 3: Project metadata setup

Render the existing project metadata with the purpose-specific view. Paste the
literal `projectRoot` value parsed in Step 2:

```bash
okstra model-io project-context --project-root /abs/path/to/projectRoot
```

If the command reports that project metadata is missing, treat that as the
"create" branch below. Otherwise, surface the rendered `Project ID` and
`Project root`, then ask whether to keep or overwrite. Default is to keep —
okstra refuses to change `projectId` on an existing project (see
`okstra_project.resolver.upsert_project_json`), so overwriting requires
manually deleting the file first.

If the file does NOT exist, ask via `AskUserQuestion`:

- **Question**: `"Project id for okstra (e.g. INV-1234, my-app, okstra)"`
- **Validate**: the answer must be non-empty AND contain at least one
  alphanumeric character. Re-ask on empty input — `okstra setup --yes`
  with no `--project-id` exits 1 with
  `error: --project-id is required (no existing project.json, not a TTY)`,
  so passing the user's empty answer through is a silent failure path.

Then create the file — paste the literal `projectRoot` from Step 2 and the literal `projectId` from the user's answer (no shell variables):

```bash
okstra setup --yes --project-root /abs/path/to/projectRoot --project-id my-project-id
```

## Step 3.5 (optional): project customisation

The built-in defaults work for most projects — skip straight to Step 4
(`doctor`) unless the user explicitly asks for one of these. When they do,
**read `references/project-config.md` next to this SKILL.md** and follow the
matching section:

- **A. worktree sync dirs** (`worktreeSyncDirs`) — extra directories symlinked
  into task worktrees.
- **B. project QA commands** (`qaCommands`, recommended) + **B.1 `qaEnv`** —
  check-only lint/format/typecheck/test baselines and the Tier 3 environment.
  Local `io` conformance is blocking; DB/HTTP/external QA is advisory and
  remains user-owned when automatic execution cannot PASS.
- **C. `.claude/settings.local.json` symlink** — automatic; read only to
  diagnose a symlink/backup warning.
- **D. PR body template** (release-handoff) — opt-in pre-registration; also
  offered on the first release-handoff run.
- **E. final report language** (`reportLanguage`) — a language tag (`en`,
  `ko`, `fr`, …); default `en`. The Phase 7 translator translates the human
  HTML into it.
- **F. declared architecture style** (`architecture.style`) — `hexagonal` /
  `layered` / `none`; hand-added, default `none`. Declaring one makes that
  architecture's placement rules binding in planning + verification.

## Step 4: Verify

```bash
okstra doctor --runtime <host-runtime>
```

If all checks return `OK`, the setup is complete. If any check fails, surface
the output and let the user decide whether to re-run install or skip.

## Step 5: Hand-off

Inform the user with a short summary:

> okstra is ready. Runtime: `~/.okstra` (version stamp). Project metadata:
> `<PROJECT_ROOT>/.okstra/project.json` (`projectId`). Run
> `/okstra-run` to start your first task.

## Failure modes

| Symptom | Cause | Fix |
|---|---|---|
| `command not found: npx` | Node missing | Install node 18+. |
| `okstra ensure-installed` keeps reinstalling | `~/.okstra/version` write fails (permissions) | Check `~/.okstra` ownership and writability. |
| `error: --project-id is required (no existing project.json, not a TTY)` | `okstra setup --yes` invoked without `--project-id`, or with empty answer to Step 3 prompt | Re-ask Step 3 and pass a non-empty id via `--project-id`. |
| `projectId mismatch` / `projectId mismatch` | `project.json` already exists with a different id | Decide which id is canonical; manually delete `<PROJECT_ROOT>/.okstra/project.json` to re-register, or re-run with the existing id. |
| `EACCES` writing under `.okstra/` | directory owned by another user (e.g. created by a previous root-shell run) | `chown -R "$USER" <PROJECT_ROOT>/.okstra` or delete and let setup recreate. |
| `warning: failed to provision .claude/settings.local.json symlink` | a non-symlink `.claude/settings.local.json` already exists and the backup-and-replace step failed | Inspect `<PROJECT_ROOT>/.claude/settings.local.json{,.bak.*}`; manually merge project-specific rules, then re-run setup. |
| `npx okstra@latest install` succeeds but `doctor` shows FAIL | runtime/{python,bin,skills} sync not yet performed (pre-release package) | Use dev install: clone the repo and run `node bin/okstra install --link <repo>`. |
