Skip to content

feat(onboard): chat-based conversational setup assistant as default zeroclaw onboard#8

Open
JordanTheJet wants to merge 22 commits into
masterfrom
zeroclaw-onboard-default
Open

feat(onboard): chat-based conversational setup assistant as default zeroclaw onboard#8
JordanTheJet wants to merge 22 commits into
masterfrom
zeroclaw-onboard-default

Conversation

@JordanTheJet

@JordanTheJet JordanTheJet commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • Base branch: master
  • What changed and why:
    • Revives zeroclaw onboard (previously a deprecation stub) as a conversational chat-based setup assistant, ported from OpenClaw's onboard --modern ("Crestodian"). It gives new users a plain-language path to inspect state and stand up their first agent without memorizing flags or section names.
    • Adds src/onboard/ with a clean split: overview (resolved-on-demand state snapshot), operation (closed command vocabulary + deterministic parser), planner (LLM fallback), execute (approval-gated executor), mod (interactive loop + --message/--json modes).
    • Deterministic-first by design: input is matched against a closed vocabulary before any LLM is consulted; the planner is reached only on unrecognized input and its output is re-parsed through the same parser, so model text can never execute outside the vocabulary. With no model configured (first run), it runs deterministic-only.
    • All user-facing output routes through Fluent (cli-onboard-* keys in locales/en/cli.ftl) per the cli_fluent_coverage architecture gate.
  • Scope boundary: Does not change quickstart (reused as the setup path), the daemon/gateway/agent runtimes, the config schema (no new fields), or provider behavior. The Tauri/web/zerocode onboarding surfaces are untouched.
  • Blast radius: Limited to the zeroclaw onboard CLI command. All config writes flow through the existing sanctioned set_prop_persistent + save_dirty path or the quickstart apply path; reads reuse doctor::run / run_configured_models and the provider factory. No new shared/cached state.
  • Linked issue(s): None.
  • Labels: Suggested: type: feature, risk: low, size: M.

Validation Evidence (required)

cargo fmt --all -- --check                  # clean
cargo clippy --all-targets -- -D warnings   # clean
cargo test                                  # all suites pass
  • Commands run and tail output:

cargo clippy --all-targets -- -D warnings: Finished ... in 30.07s (no warnings).

cargo test (full root battery, all green):

test result: ok. 230 passed; 0 failed   (architecture — includes cli_fluent_coverage)
test result: ok. 281 passed; 0 failed   (bin: onboard parser + CLI)
test result: ok. 188 passed; 0 failed
test result: ok. 159 passed; 0 failed
test result: ok.  19 passed; 0 failed
test result: ok.   9 passed; 0 failed
test result: ok.   3 passed; 0 failed
  • Beyond CI — what did you manually verify? Built the debug binary and exercised it against a live config: onboard --json and onboard --message "status" resolve agents/providers (with per-provider key presence)/gateway reachability; persistent ops (set up an agent) print an approval plan and apply nothing without approval. Live planner verified with a real model: a free-form request ("give me the lay of the land") routed through the LLM planner to overview (executed), and "what should I do first?" routed to setup (plan printed, correctly gated). Localized output (help, agents, gateway status, plans) renders with all Fluent keys resolved.
  • If any command was intentionally skipped, why: None — the full cargo test battery was run.

Security & Privacy Impact (required)

  • New permissions, capabilities, or file system access scope? No — reads the existing config path and writes config only through the same sanctioned setter zeroclaw config set uses.
  • New external network calls? Yes — a bounded (~2s) health probe to the user's locally-configured gateway /health, and the LLM planner call to the user's already-configured model provider (only on free-form input when a keyed provider exists). Both target endpoints the user already configured; no new third-party endpoints.
  • Secrets / tokens / credentials handling changed? No — secrets are never printed; the approval-plan redaction uses the schema's canonical Config::prop_is_secret; keys are read from existing config and handed to the existing provider factory.
  • PII, real identities, or personal data in diff, tests, fixtures, or docs? No.
  • If any Yes, describe the risk and mitigation: Planner output is untrusted model text — re-validated through the deterministic parser (cannot execute outside the closed vocabulary) and stripped of control/escape characters before display; all state-changing operations require explicit approval.

Compatibility (required)

  • Backward compatible? Partiallyzeroclaw onboard changes behavior: it was a deprecation stub and now launches the chat assistant. quickstart is unchanged.
  • Config / env / CLI surface changed? Yes (CLI only)onboard now accepts --message/--json/--yes and no longer accepts the removed legacy flags (--quick, --force, --reinit, --api-key, --model-provider, --model, --memory, --<section>-only, positional section subcommands). No config or env changes.
  • If No or Yes to either: exact upgrade steps: Scripts that invoked zeroclaw onboard with legacy flags should switch to zeroclaw quickstart (guided agent creation) or zeroclaw config set <path> <value> (headless). Bare zeroclaw onboard now opens the interactive assistant (TTY required); use --message "<request>" or --json for non-interactive use.

Rollback (required for risk: medium and risk: high)

Low-risk: git revert <sha> restores the prior deprecation stub. The change is isolated to the onboard command path.

Supersede Attribution (required only when Supersedes # is used)

N/A — not superseding any PR.

@github-actions github-actions Bot added the core label Jun 19, 2026
@JordanTheJet JordanTheJet added the enhancement New feature or request label Jun 19, 2026
@JordanTheJet
JordanTheJet force-pushed the zeroclaw-onboard-default branch from 75385c5 to 8728720 Compare June 20, 2026 00:12
…zeroclaw onboard`

Replace the deprecated `zeroclaw onboard` stub with a conversational
setup/repair assistant (ported from OpenClaw's "Crestodian"). Bare
`zeroclaw onboard` opens an interactive chat loop; `--message <text>`
runs one request non-interactively; `--json` dumps the overview snapshot.

New `src/onboard/` module:
- overview: resolved-on-demand snapshot of config/agents/providers/gateway,
  with formatter + JSON + next-step hint. No cached state.
- operation: closed command vocabulary + deterministic parser; persistent
  ops are classified for approval gating.
- planner: LLM (chat_with_system) reached only when deterministic parse
  fails; output re-validated through the same parser so model text can
  never execute outside the vocabulary. Deterministic-only when unconfigured.
- execute: approval-gated executor reusing doctor::run /
  run_configured_models / run_quickstart_cli / set_prop_persistent.

Config writes flow exclusively through set_prop_persistent + save_dirty or
the quickstart apply path (single source of truth). Secret redaction uses
the schema's canonical prop_is_secret. All user-facing output routes
through Fluent (cli-onboard-* keys in locales/en/cli.ftl) per the
cli_fluent_coverage gate. main.rs: slim Onboard clap variant to
--message/--json/--yes, drop the deprecation block, add the dispatch arm,
refresh the onboard CLI tests.
…list

`setup` (and "create agent") now run a minimal detect-first flow rather than
launching the full quickstart wizard:

- already-usable install (a provider with a model exists) → ask only the
  agent name, then bind a new agent to that provider.
- fresh install → pick provider (key prompt skipped for local/keyless) →
  masked API key → model (catalog default = newest via the chat-rank sort,
  or free-text) → agent name → plan → approve.

Everything else is defaulted (balanced risk, sqlite memory, no channels,
empty system prompt) and landed through the canonical apply_with_surface
path. Setup is now self-gated (TTY check + its own approval), so it is no
longer a generic persistent op; non-interactive `--message setup` prints
guidance instead of hanging. Adds cli-onboard-setup-* Fluent keys.
Address the rough edges from real use of the conversational onboard:

- setup now shows an editable review (change provider / key / model / name,
  Esc to back out) before anything is written — no more one-way prompt march.
- `talk to agent` launches `zeroclaw agent --agent <alias>` (inheriting the
  terminal and ZEROCLAW_CONFIG_DIR) after a quick confirm, instead of only
  printing the command to copy.
- greetings (hi/hello/thanks) get a friendly reply; help phrasings (help me,
  can you help, what can you do) map straight to help without needing the
  model; unrecognized input gets a warmer, actionable hint.

Adds cli-onboard-* Fluent keys and parser tests for greetings/help.
Setup now gathers a little identity before writing, so a new agent feels
personal instead of blank:

- after provider/model, ask the agent's name, your name, a communication
  style, and an autonomy (risk) level — all with defaults you can Enter
  through, and all editable on the review screen.
- those answers render the agent's personality markdown (SOUL/IDENTITY/
  USER/…) from the default template via render_preset_default, staged
  through the canonical apply_with_surface path.

Adds cli-onboard-* Fluent keys for the new prompts/labels.
Add a `create_agent` tool so a running agent (e.g. an onboarding persona)
can create a NEW agent — name, model provider + model, autonomy level, and a
personalized identity — by landing a BuilderSubmission through the canonical
quickstart apply path. Writes config only; does not run the new agent.

Safety mirrors the other config-mutating tools and adds two guards:
- create-only: refuses if an agent with that name already exists, so it can
  never overwrite or escalate an existing agent's profile.
- no self-modification: refuses if the target name equals the calling agent.
Plus the usual risk-profile allowlist gate and the shared action budget.

Registered in all_tools_with_runtime with the caller alias; attributed
centrally. Unit tests cover each guard.
Revert the identity Q&A out of `setup`: gathering the agent name, your name,
communication style, and autonomy level made the flow as long as quickstart,
the opposite of the goal. `setup` is again the short path — pick provider,
enter the key (skipped for local), pick a model, review, apply — and that
identity/personality work moves to the upcoming `setup_assistant` agent, who
gathers it conversationally and suggests sensible defaults.
After `setup` configures a model (provider/key/model only), it now spins up a
bundled `setup_assistant` agent and launches her interactive session — she
gathers what the user wants and builds their real agent conversationally,
instead of setup interrogating them up front.

- setup_assistant is created bound to the chosen provider with her own
  bundled personality (IDENTITY/SOUL/AGENTS/USER) and a locked-down risk
  profile: Supervised autonomy with allowed_tools = [create_agent, ask_user]
  only. She can build agents and ask questions, nothing else.
- she uses the create_agent tool to write the user's agent (name, model,
  risk, personality woven from their name + style) and points them at
  `zeroclaw agent --agent <name>`.
- launched via the existing subprocess helper; her REPL + ask_user run over
  the CLI channel.
The bundled onboarding agent is now 'Zerona, the agent builder' (alias
`zerona`). Her persona files, the handoff line, and failure message all
name her. She runs at `full` autonomy so her two allowed tools
(create_agent + ask_user) don't trigger an approval prompt mid-chat —
the conversation is the approval, and the registry filter still bars
every other tool regardless of autonomy.
The interactive approval prompt now reads "<alias> wants to execute: …"
instead of a generic "Agent wants to execute", so the operator can see
which agent is asking. ApprovalManager carries an optional agent_label
(set from the agent alias at construction); a blank/absent label keeps
the old 'Agent' fallback.
Adds a start_agent tool that launches a configured agent's interactive
session in the current terminal (zeroclaw agent --agent <name>) and
returns control to the caller when it ends. Zerona uses it to switch the
user straight into the agent she just built, instead of only printing the
command. Gated like create_agent (risk-profile allowlist + Act budget),
plus an interactive-TTY guard so it never spawns a session headless and a
no-self-launch guard. Existence is checked against a fresh on-disk config
so an agent created earlier in the same session is found. Added to
Zerona's allowlist and her playbook (offer to start it on success).
Addresses review feedback (zeroclaw-labs#8033): two categories of user-facing strings
bypassed the locale bundle because the cli_fluent_coverage source scan
can't see strings stored in enum fields or built ad hoc in a formatter.

- operation::parse() now resolves the empty-input, unknown-input, and
  quit/exit ("Bye.") hints through crate::t at parse time, so the
  Operation::None::message printed verbatim by execute/mod is already
  localized. Adds the cli-onboard-empty-input / -bye / -unknown-input keys.
- Overview::format() and next_step() now route every surface string
  (Config/Path/Default model labels, present/missing, agent + provider
  rows, Gateway/Service/Planner states, Config issues, Next) through the
  bundle, reusing the existing reachable/running/agent-row keys and adding
  cli-onboard-ov-* / cli-onboard-next-* keys. next_step() returns String.
- New operation::tests::none_messages_route_through_fluent closes the
  enum-field blind spot the reviewer flagged: each None message must equal
  its crate::t(<key>) resolution.

Config-issue lines still print the zeroclaw-config crate's own warning
strings verbatim; localizing those is a separate cross-crate change.
@JordanTheJet
JordanTheJet force-pushed the zeroclaw-onboard-default branch from a374103 to 1dbd046 Compare June 21, 2026 09:54
JordanTheJet and others added 9 commits June 21, 2026 06:05
Minimal `setup` applies the model and hands off to Zerona; it no longer
creates the agent itself, so the review menu's "Apply — create the agent"
was misleading. It now reads "Apply — set up the model & start the agent
builder." Also drops the now-unreferenced day-1 setup keys (name prompt,
create/created-agent plan/done, review-agent row, rename action) left over
from the pre-Zerona flow.
Before, the handoff dropped the user at an empty agent prompt with nothing
to go on, so they'd type "hi" and get a terse reply. Onboard now prints
Zerona's opening question (with example use-cases) right before launching
her session, so the user knows exactly what to say. Her persona is updated
to treat the first message as the answer to that question and not
re-introduce herself, keeping it one continuous conversation.
Zerona, the agent builder, gains file_read/file_edit/file_write alongside
create_agent/start_agent/ask_user. With her existing `full` autonomy
(which disables workspace_only), she can now read and edit the config TOML
and any agent's personality files directly — configuring runtime_profile,
memory, channels, peer_groups, risk level, and the SOUL/IDENTITY/USER/
TOOLS/HEARTBEAT files, not just the structured create_agent fields.

Her AGENTS.md is now built per-install with the real config path and
agents workspace dir baked in, and guides her to scaffold with
create_agent (SQLite + balanced defaults) then file_edit for the rest —
reading first and keeping the TOML valid. Agents default to SQLite memory
and balanced risk; she offers `yolo` (full autonomy) for hands-off use.

Her own identity is now a cheerful icy crab who loves helping people build
ZeroClaw agents.

Security note: this makes Zerona a high-privilege agent — full autonomy +
file write across the install with no approval gate. Her allowlist is the
boundary, granting exactly the builder + file tools; the deliberate
tradeoff for a self-invoked, conversational agent builder.
…al-gated

Replaces the agents-dir-only restriction with the Claude-Code security
model: broad capability, scoped working area, human approval on the
dangerous path.

- She can edit config.toml flexibly (runtime_profile, memory, channels,
  peer_groups, risk) plus all agents' personality files.
- Working area is scoped: supervised (not full) + workspace_only +
  allowed_roots granting only the config dir and the agents dir — she
  can't reach anything outside the ZeroClaw install (no /etc, no SSH keys).
- create_agent (create-only, can't escalate an existing agent) stays
  auto-approved; the raw file_write/file_edit tools are NOT auto-approved,
  so every config edit that could rewrite a risk profile or allowed_tools
  surfaces an approval prompt (naming her + the path), with Always to
  allow-list for the session. A permission-changing edit can never happen
  silently.

Test asserts the boundary: supervised + workspace_only + config/agents
allowed_roots + file_write/file_edit excluded from auto_approve.
- Setup Apply action reads 'Apply — start the agent builder'.
- Zerona's opening question drops the 'in one sentence' constraint and the
  canned examples; it now invites the user to say as much or as little as
  they like, in her cheerful crab voice.
…steps

- create_agent failed its first call because Zerona's persona used a literal
  example provider 'anthropic.default'. The actual configured reference (e.g.
  openai.default) is now resolved from the model_provider choice and baked
  into her AGENTS.md, so she passes the right provider on the first try.
- Persona now tells her to be honest about what a freshly built agent still
  needs to actually work — outside data (email/calendar/web) and a schedule
  are off by default — and to lead the user through wiring them step by step
  rather than implying the agent already works.
Reframes Zerona's persona around a WORKING agent, not just a scaffolded
one. After create_agent she now drives the remaining configuration herself
over as many turns as it takes: file_read the config, ask_user for any
required inputs (account/key/schedule/channel), file_edit config.toml to
wire tools / data sources / channels / a schedule, and re-read to verify.
She only claims the agent is ready (and offers to start it) once it can
actually do its job; otherwise she states exactly what's left and what she
needs. No more over-claiming or stopping at scaffolding.
…lders

Adds a read-only config_help tool that returns the field table (name,
type, description, default) for any config section, rendered live from
schemars::schema_for!(Config) via the existing schema_markdown machinery —
the same source as the published docs, so it never goes stale. Omit the
section to list all top-level sections.

The schema is built in zeroclaw-config via a new config_schema_root()
helper (gated by that crate's schema-export, which the binary enables), so
the tool works in the shipped binary without relying on the runtime's
schema-export feature — the binary builds zeroclaw-runtime with
default-features off, which would otherwise compile the tool's body out.

Wired to Zerona: added to her allowlist + auto_approve (read-only), and her
persona now tells her to consult config_help before editing any config
section whose keys she's unsure of — so she configures config.toml from the
real schema instead of guessing (which is why her first create_agent earlier
tried a non-existent anthropic.default).
singlerider added a commit that referenced this pull request Jun 27, 2026
…uzzySelect

The bug-1 fix (FuzzySelect rewinds the cursor past its painted block and erases
scrollback above the menu, worst on double-width CJK) was applied to
run_onboard_tree/CliSurface but NOT to run_quickstart_cli, the handler behind
`zeroclaw quickstart` — the very command the onboard deprecation notice steers
users toward. That path was a separate hand-rolled flow still calling raw
FuzzySelect::new() on all 12 menu pickers, with no theme and a raw Password for
secret entry, so the cursor-erase (#1), missing styling (#7), and secret-repaint
(#8) defects shipped live there while the driver guard only exercised the fixed
onboard tree.

Extract the theme and a themed Select helper (onboard_select /
onboard_select_default) to module scope, reuse them from CliSurface (removing the
duplicate inline theme/select), and convert every run_quickstart_cli picker plus
the shared prompt_for_field enum picker and pick_preset to onboard_select. Each
row is fit to one terminal line via fit_select_item so the 1-row-per-item clear
arithmetic holds at any width and locale. Secret entry already routed through the
in-place masked_secret. No FuzzySelect remains in the onboard/quickstart flow;
the only one left is the config-set model-id catalog picker, where fuzzy filter
over a long model list is intentional.

Bin builds with onboard; fmt + clippy clean; onboard suite 47 green.
Resolve conflicts in cli.ftl (keep both onboard + daemon/ctxwin string blocks)
and approval/mod.rs (keep agent_label param, fold in master's terminal-vs-stdin
doc wording). Workspace cargo check passes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants