---
description: First-session onboarding walkthrough; verifies the install, offers optional setup (Atlassian, workspace, alias, profile intake), and marks each step complete.
when_to_use: >-
  Run on the operator's first session in a fresh scaffolded PA instance. Also
  re-runnable any time later: every step is idempotent and reads the current
  state from `.session/onboarding.json`, so `/onboard` picks up where it left off
  and skips steps already marked done.
allowed-tools: Bash, Read, Write, Edit
argument-hint: (no arguments)
context: inline
---

# /onboard; first-session walkthrough

You are running the onboarding walkthrough for a freshly scaffolded PA instance.
The scaffold has already run `pnpm install` and `pa status` at scaffold time, so
the install is proven working. Your job is the second half: verify the runtime,
offer the optional setup steps the guide deliberately left for you, and hand
over. Every step below is idempotent. State lives in `.session/onboarding.json`
so re-running `/onboard` picks up where it left off.

## State file

Read `.session/onboarding.json` first. Shape:

```
{
  "version": 1,
  "startedAt": "<iso>",
  "steps": {
    "verifyRuntime":     "pending" | "done" | "skipped",
    "verifyVersion":     "pending" | "done" | "skipped",
    "profileIntake":     "pending" | "done" | "skipped",
    "aliasOffer":        "pending" | "done" | "skipped",
    "workspaceOffer":    "pending" | "done" | "skipped",
    "librarianSchedule": "pending" | "done",
    "vault":             "pending" | "done" | "notNeeded",
    "atlassianOffer":    "pending" | "done" | "skipped"
  },
  "completedAt": null | "<iso>"
}
```

`librarianSchedule` never lands on `skipped`. It is a mandatory step and
onboarding does not complete until it is `done`.

`vault` never lands on `skipped` either. It is conditionally mandatory:
required (must be `done`) whenever at least one enabled tool declares a
secrets need (see `packages/core/src/vault/tool-needs.mjs`), and set to
`notNeeded` when the tool-needs cross-reference is empty. Both `done`
and `notNeeded` pass the completion gate.

If the file is missing, the scaffold did not seed it; flag that and stop.

If `completedAt` is set, tell the operator onboarding is already complete and
offer to re-run a specific step by name. Do not walk the whole flow again.

## Flow

Walk the pending steps in this order. After each, write the state file back
with the step marked `done` or `skipped`. Keep exchanges short: one question,
one answer, move on.

### 1. verifyRuntime

Run `pnpm exec pa environment` and read the resulting `.session/environment.json`.
Report Node version, pnpm version, git version, and workspace state in one line.
If Node is below 24 or pnpm below 9, name the gap and stop; the operator needs
to upgrade before continuing.

### 2. verifyVersion

Run `pnpm exec pa status` and capture the installed package version. Compare
against `npm view @stravica-ai/digital-operator-pa version`. On a match, mark
done and move on. On a mismatch, print both versions and the recovery line
(`pnpm install` inside the instance); do not attempt the fix yourself.

### 3. profileIntake

Ask the operator four questions in one turn. Question 4 is optional
and explicitly skippable; a first-day operator often has no strong
answer and a forced answer here becomes a stale steering signal for
the whole life of the instance. "Skip" is the safe default when the
operator hesitates.

1. Your name and how you prefer to be addressed?
2. Your role (job title, or "solo", or a short description)?
3. Communication style you want (formal, casual, direct, verbose)?
4. (Optional, skip freely) Anything you would like the PA to lean into
   right away? A one-line hint about the kind of work you plan to
   throw at it (writing, code, admin, research, planning). This tunes
   nothing critical; the PA discovers your patterns as it goes.

Take the answers and write them into `operator/profile/profile.md`,
overwriting the placeholder. Keep it a short human-readable paragraph
plus a bulleted list of preferences. If Q4 was skipped or the answer
is `skip` / empty, do not write a Q4 line at all. Do not invent fields
the operator did not name.

Also update `operator/config/preferences.json` in the SAME turn: replace
the placeholder `operator.role: "Operator"` seeded by the scaffold with
the role the operator actually gave (Q2). This is what the workspace
overview endpoint and every downstream reader consult; leaving it as
`"Operator"` reads as "onboarding did not take" on the home page even
after the profile prose is written. If Q2 was answered `"solo"`, write
`"solo"` verbatim. Preserve the file's 2-space indent so subsequent
diffs stay clean. Do not touch any other field.

### 4. aliasOffer

The colleague probably has not aliased the PA yet. Offer one line and let them
decide whether to run it. The exact command is:

```
echo "alias <pa-name>='cd <target-dir> && pnpm exec pa session'" >> ~/.zshrc && source ~/.zshrc
```

Substitute `<pa-name>` from `operator/config/preferences.json` and
`<target-dir>` from `process.cwd()`. If the operator says yes, print the exact
line to run; do not run it for them (their shell rc is not our file to write).

### 5. workspaceOffer

Ask if they want the local workspace started now. On yes, run
`pnpm exec pa workspace start` in the background. The CLI auto-probes
for a free port when the configured one is busy (starting at
max(configured+1, 4210), up to 20 attempts) and persists the chosen
port to `operator/config/preferences.json:workspacePort`, so no manual
port dance is needed. Print the URL from the resulting preferences
file (the workspace start command's own output also names the chosen
port).

Pass `--port <N>` when the operator wants a specific port, or
`--no-probe` to keep the strict hard-fail behaviour instead of the
auto-probe.

On no, note that `pnpm exec pa workspace start` is the verb whenever
they want it.

### 6. librarianSchedule (mandatory, no opt-out)

The distillation sweep is what turns staged observations under
`agents/<paName>/staging/` into knowledge docs under
`operator/knowledge/`. Without a scheduled sweep the whole self-learning
loop dies silently: staged notes pile up, no docs get promoted, and
`pa knowledge search` never sees the new material. The scaffold ships
the schedule file at `schedules/<paName>-distillation-sweep.json`; this
step installs it on the OS-native backend and fires one real run to
prove the wiring.

Do NOT ask the operator whether to do this. State what is happening in
one short paragraph:

> Installing the librarian distillation sweep so your Digital Operator
> keeps learning. It runs every four hours in the background, turns your
> staged observations into knowledge docs, and refreshes the retrieval
> graph so the new material is searchable straight away. This is the
> one piece of scheduling every solo instance needs.

Then run:

```
pnpm exec scheduler install schedules/<paName>-distillation-sweep.json --force-host
```

Substitute `<paName>` from `operator/config/preferences.json`. The
`--force-host` is deliberate. macOS hostnames flap between the DHCP
name and the configured name (Dex 2026-07-16 evidence), and a well-
formed refusal at first-run onboarding is the worst possible operator
experience.

Immediately after install, trigger one real sweep through the scheduler
backend itself (never a shell repro: a shell resolves `node` and PATH
differently and would hide the launchd/cron spawn behaviour the ledger
is meant to prove). On macOS/launchd:

```
launchctl kickstart -k "gui/$(id -u)/com.<paName>.<paName>-distillation-sweep"
```

On Linux/cron, invoke the exact command line the crontab entry carries,
from the same working directory, with a minimal PATH the cron job would
see:

```
env -i HOME="$HOME" PATH=/usr/local/bin:/usr/bin:/bin \
  bash -c 'cd <targetDir> && node node_modules/@stravica-ai/digital-operator-pa/bin/distill run'
```

Wait for the run with a hard timeout of 6 minutes (a real sweep with
one `claude --print` subprocess is typically 60–120 seconds, but the
first-ever run on a cold cache can stretch). Poll
`.cache/distill/logs/runs.jsonl`. A completed run appends one JSON line
with `"status": "ok"` or `"status": "noop-empty-staging"`. Either
status is a successful proof: the pipeline ran end to end.

Mark this step `done` only when the ledger shows a completed run. If
the install fails, or the run times out, or the ledger records a
`fail-*` status, this step is NOT `done`, onboarding does NOT complete,
and the operator gets:

1. The exact error message (from the scheduler CLI's stderr, or the
   ledger's `reason` field, or a timeout notice).
2. The one command to retry, verbatim:
   `pnpm exec scheduler install schedules/<paName>-distillation-sweep.json --force-host`

Then stop. Do not silently skip to `atlassianOffer`. The whole
onboarding is blocked on this step.

**Hard stop between step 6 and step 7.** Do not deliver the step-7
vault pitch, do not describe the vault, do not ask the operator for
credential values, and do not print the `secrets init` invocation while
`librarianSchedule` is anything other than `done` in the state file.
Step 7 is only reached AFTER `librarianSchedule` transitions to `done`
and a completed run is recorded in `.cache/distill/logs/runs.jsonl`.
If the operator asks about the vault in the meantime, name the pending
check (`librarianSchedule` awaiting a proven run) and pick step 7 back
up once the librarian step lands. A pre-emptive step-7 pitch reads to
the operator as a step already begun, and the vault step's first-time
material is expensive to redo cleanly if it lands under the wrong
prerequisite.

### 7. vault (conditionally mandatory, no opt-out)

Stand up the credentials store when an enabled tool declares a secret
need. The signal comes from
`packages/core/src/vault/tool-needs.mjs::enabledToolsNeedingSecrets(repoRoot)`:
cross-references the enabled tools in
`operator/extensions/manifest.json` against the registry. Atlassian is
the shipping default and declares `JIRA_DOMAIN`, `JIRA_EMAIL`,
`JIRA_API_TOKEN`.

If the cross-reference is empty (no credentialed tool enabled), mark
this step `notNeeded` and move on. `pa onboard complete` treats
`notNeeded` as a clean pass.

Otherwise, name the keys the enabled tools declare and route the
operator to a purpose-built secret-handling surface. Two ship in every
install and both keep values off the conversation:

- The workspace **Secrets** page; nav id `secrets`, at
  `<workspace>/secrets.html`.
- The `secrets` CLI in the operator's own terminal, using the stdin
  form: `pnpm exec secrets set <KEY> -`. The value is typed at the
  terminal, never in chat.

Never ask the operator to paste a value into the conversation.
Barry's ruling 2026-09-21: "The instructions should guide the user to
use either the `secrets` CLI, or the workspace secrets UI. It shouldn't
ask the user to paste anything." The step's job is to route to a
surface, not collect values.

Say something like:

> Atlassian needs three credentials before it can talk to Jira: your
> site domain, your account email, and an API token (create one at
> https://id.atlassian.com/manage-profile/security/api-tokens). Add
> them either on the **Secrets** page in your workspace, or with
> `pnpm exec secrets set <KEY> -` in your terminal. Tell me when they
> are in and I will check they resolved.

Then wait. When the operator confirms, verify value-blind and gate
completion on the checks passing:

```
pnpm exec secrets get JIRA_DOMAIN --exists
pnpm exec secrets get JIRA_EMAIL --exists
pnpm exec secrets get JIRA_API_TOKEN --exists
```

Each should print `present`. If any prints `absent`, name the missing
key and ask the operator to add it via the same surface they used
first, then re-run the checks. Only mark the step `done` when every
required key resolves `present`.

Internals (SOPS, age, key file paths, encrypted-store layout, stdin
piping) are revealed ONLY on explicit operator request. The operator
talks to the vault in terms of the two interfaces above, and the PA
follows that lead.

### 8. atlassianOffer

Ask if they use Jira or Confluence at all. On no, mark skipped. On yes,
verify the tool works end-to-end now that the vault is stood up:
`pnpm exec jira auth` and `pnpm exec confluence auth`, and report the
identity each returns. If either exits 2 with `vault not initialised`,
re-run the vault step above with the missing keys added to the JSON
object.

## Completion

When every step is done or skipped, run `pnpm exec pa onboard complete`.
The verb refuses when any mandatory step is not `done`, naming the
pending step and its remediation; otherwise it stamps `completedAt` in
`.session/onboarding.json` with a 2-space indent. Never hand-edit the
file. The mandatory steps are:

- `librarianSchedule` (always mandatory)
- `vault` (mandatory when an enabled tool declares a secrets need;
  `notNeeded` is a clean pass when nothing does)

Tell the operator onboarding is done. Give them one line: "You are
ready. Ask me anything, or say `bring me up to speed` and I will run
the standard session-boot briefing."
