# CyberBrain26 quickstart

Every command in this document exists. If a command is not listed here, it does not exist
in the CLI.

## 1. Prerequisites

| Requirement | Detail |
|---|---|
| OS | Linux. The execution path is Bubblewrap-only and fails closed elsewhere. |
| Python | 3.11 or newer (`pyproject.toml`, `requires-python = ">=3.11"`). |
| Bubblewrap | The `bwrap` binary on `PATH`. Hard prerequisite for running any code. |

Verify Bubblewrap is present:

```bash
bwrap --version
```

If `bwrap` is missing, `cyberbrain run` refuses every step with a `RuntimeError` stating
that it is "refusing to run code without a sandbox". There is no unsandboxed fallback, by
design. `cyberbrain doctor check` reports this as a `fail` row.

## 2. Install

```bash
git clone <your repository url>
cd CyberBrain26-v4
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e .
```

Confirm the console script is on `PATH`:

```bash
cyberbrain version
```

Optional, for development:

```bash
python -m pip install -e ".[dev]"   # pytest, ruff, mypy
```

## 3. Check the installation

```bash
cyberbrain doctor check
```

Thirteen read-only checks: Python version, package version, platform support, data
directory, database, retention, Bubblewrap, sandbox limits, policy mode, agent scopes,
pending approvals, quality gates, model providers. It creates nothing, migrates nothing,
never changes the policy mode, and never prints an environment variable *value* — only
`true`/`false` presence flags for a short list of conventional credential names.

Useful flags:

```bash
cyberbrain doctor check --json      # machine-readable report
cyberbrain doctor check --strict    # treat WARN as FAIL, exit 1
```

Two honest limits of `doctor`, straight from its own output: it is a *configuration
self-report* produced by the installation, not verified security evidence, and it never
verifies a running end-to-end agent task or contacts a model provider.

## 4. Choose where local state lives

The data directory holds the SQLite database, `roadmaps.json` and the sandbox workspaces
root. Set it once in your shell (the application never reads `.env` files):

```bash
export CYBERBRAIN_DATA_DIR="$HOME/.local/share/CyberBrain26"
```

`--data-dir` overrides it per command. `CYBERBRAIN_DB_PATH` overrides the database file.
See `.env.example` for all four supported variables.

## 5. Try `plan` — and see why it is not the next step

```bash
cyberbrain plan --goal "compute a mean of 1..10" --id demo
```

This writes a roadmap to `$CYBERBRAIN_DATA_DIR/roadmaps.json`. Two things you must know
before you continue:

- The planner currently emits a **hardcoded placeholder plan**. It does not reason about
  your goal.
- Every step it stores has a payload **without an `action` key**.

`run` refuses any step whose payload declares no action — there is nothing to authorize
otherwise — so `plan` -> `run` is a **dead end today**, and no CLI command can currently
produce a runnable roadmap:

```bash
cyberbrain run --id demo --scopes python
# Step 'step-1' declares no 'action' in its payload, so there is nothing to
# authorize. It was refused; add an explicit action to the step payload and try
# again. No default action is ever inferred.
# exit code 1
```

To get a runnable step you must write `roadmaps.json` yourself. This is the current, and
only, way to produce an executable roadmap.

## 6. Write a runnable step by hand

A step payload is authorized by its `action`, and the code keys consumed by the coder
agent are `code`, `language` and the optional `workspace` and `timeout_seconds`. The
`action` must be one of the mapped actions below, and the identity must hold the matching
scope.

Valid `action` -> required `--scopes` value:

| `action` | required scope | notes |
|---|---|---|
| `execute_python` | `python` | sensitive: requires approval |
| `execute_shell` | `shell` | sensitive: requires approval |
| `read_file` | `read_file` | not sensitive in SAFE mode |
| `write_file` | `write_file` | sensitive |
| `delete_file` | `delete_file` | sensitive |
| `access_network` | `network` | sensitive |
| `access_secrets` | `secrets` | sensitive |
| `execute_docker` | `docker` | sensitive |
| `access_browser` | `browser` | no execution backend exists |
| `execute_git` | `git` | no git execution path exists |
| `access_mcp` | `mcp` | no MCP server exists |
| `audit_log` | `audit` | read the audit trail |

Sensitive actions are refused unless approved, because SAFE mode routes everything in
`SENSITIVE_ACTIONS` to `require_approval`.

### The workspace rule

A `workspace` is bind-mounted **read-write**, so it must be an existing directory **inside
the sanctioned workspaces root**, which is `<data dir>/workspaces` by default. A workspace
anywhere else is refused *before any process starts* — this is a deliberate control, not
a bug. If you set `CYBERBRAIN_WORKSPACES_ROOT`, that becomes the root instead.

The sandbox resolves this root from the environment, so `CYBERBRAIN_DATA_DIR` must be
exported (the `--data-dir` flag alone does not move the sandbox root).

### Complete, verified example

```bash
export CYBERBRAIN_DATA_DIR="$HOME/.local/share/CyberBrain26"
DATA_DIR="$CYBERBRAIN_DATA_DIR"

# The workspace must live inside <data dir>/workspaces.
mkdir -p "$DATA_DIR/workspaces/demo"

cat > "$DATA_DIR/roadmaps.json" <<'JSON'
{
  "demo": {
    "id": "demo",
    "name": "demo",
    "status": "pending",
    "steps": [
      {
        "id": "s1",
        "role": "coder",
        "description": "write a marker file in the workspace",
        "payload": {
          "action": "execute_python",
          "code": "open('/workspace/ran.txt', 'w').write('executed')",
          "language": "python",
          "workspace": "/home/you/.local/share/CyberBrain26/workspaces/demo"
        },
        "depends_on": [],
        "status": "pending"
      }
    ]
  }
}
JSON
```

Replace the `workspace` value with your real absolute path. Field requirements:

- top level: roadmap id -> `{id, name, status, steps}`; `id` and `name` are required.
- step: `id`, `role`, `description`, `payload` are required. `role` must be one of
  `planner`, `coder`, `evaluator`, `security`, `research`, `browser`; use `coder` for code.
- step `payload`: `action` (mandatory), `code`, `language` (`python`/`py` or `shell`/`sh`),
  `workspace`, `timeout_seconds` (optional, default 30).
- step `depends_on`: list of step ids; a step whose dependency did not succeed is **not
  dispatched**.
- step `status`: `pending`, `dispatched`, `completed`, `failed`, `blocked`.
- roadmap `status`: `pending`, `running`, `completed`, `failed`, `blocked`, `cancelled`.

An unknown roadmap id, a corrupt `roadmaps.json`, a non-object index, duplicate step ids
or an unknown status value are all refused with a message and exit code 1. No step is
dispatched in any of those cases.

## 7. Run it, with the two-terminal approval flow

`run` never approves anything itself. Start it in terminal A:

```bash
cyberbrain run --id demo --scopes python
```

`execute_python` is a sensitive action, so the run stops at the approval gate and waits
(up to `--approval-timeout`, default 300 s). In terminal B, on the *same* data directory:

```bash
cyberbrain approvals pending
cyberbrain approvals show <request-id>     # read the full request before deciding
cyberbrain approvals approve <request-id>  # or: approvals deny <request-id>
```

Approving lets the waiting run proceed; denying (or letting the timeout expire) makes it
fail. Both terminals must point at the same store — same `--data-dir` / `--db`, or the
same exported `CYBERBRAIN_DATA_DIR`. `approvals` defaults `--no-persist` to false; with it
set, a decision is not written to disk and cannot unblock a run in another process.

The step then executes inside Bubblewrap and the marker file appears:

```bash
cat "$CYBERBRAIN_DATA_DIR/workspaces/demo/ran.txt"
# executed
```

The final line of the run reads: `Roadmap 'demo' completed: 1 step(s) executed and
authorized. No model was called; only declared actions ran.`

Audit the decisions afterwards:

```bash
cyberbrain approvals history
```

Note what the approval record does *not* do: it is bound to the request id, action,
resource and context only. It is **not** cryptographically bound to the code that runs, so
it cannot prove which concrete payload the approval was spent on.

## 8. When something is refused

| Message | Meaning | What to do |
|---|---|---|
| `coder scopes: (none)` then a step failure | the scope gate closed the step; the identity holds no scope | pass `--scopes python` (or `shell`) |
| `declares no 'action' in its payload` | nothing to authorize, by design | add `action` to the step payload |
| `depends on ..., which did not succeed` | the step was never dispatched | fix the predecessor, or drop the dependency |
| `Agent ptah-coder lacks required scope 'python'` | identity scope gate | grant the scope explicitly |
| `Approval unavailable for action '...'` | no approval manager on the store | check `--data-dir` / `--db` point at a real SQLite store |
| `Approval cancelled/expired for action '...'` | the wait timed out | raise `--approval-timeout`, or approve faster |
| `refusing to run code without a sandbox` | Bubblewrap missing or unresolvable | install `bwrap`; there is no host fallback |
| `workspace ... is outside the allowed workspaces root ...` | the read-write mount was refused | move the workspace under `<data dir>/workspaces` |
| `code and language must be strings` | payload shape rejected before the provider | `code` and `language` must both be JSON strings |
| `Roadmap '...' was not found` | unknown id | `cyberbrain plan --id <id> ...` or hand-write `roadmaps.json` |

Every refusal is audited, and no refusal ever prints success wording.

Expect noise on stderr: when a dispatched step is denied, the libraries below the CLI log their own diagnostics, including a Python traceback, at ERROR level. That is deliberate operational logging (see the module docstring in `src/cyberbrain26/cli.py`), not a crash — the command still exits non-zero and prints no success wording.

## 9. What is not covered by this quickstart

- No HTTP API, web UI, TUI or MCP server exists. See `docs/CAPABILITIES.md`.
- No model is called by `plan` or `run`; `--model` / `--lang` no longer exist.
- No git worktree, diff review or merge step exists. Review changes yourself.
- macOS/Windows: `doctor` and `approvals` work, `run` does not.

## 10. Run the tests

```bash
PYTHONPATH=src python3 -m pytest -q
```
