Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .agents/skills/developing-vm-cli/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
name: developing-vm-cli
description: "Develop the guest CLI (claw) that runs inside the VM. Use when working on vm-cli commands, the JSON output protocol, doctor checks, CapabilityContext implementation, or the capability registry."
---

# Developing the Guest CLI (claw)

`claw` is a compiled TypeScript binary deployed into the VM at
`/usr/local/bin/claw`. The host CLI invokes it via `driver.exec()` and
gets structured JSON back.

## Package structure

- `bin/claw.ts` — entry point (commander dispatch)
- `src/exec.ts` — execa wrapper
- `src/output.ts` — JSON envelope helpers (`log`, `ok`, `fail`)
- `src/capabilities/registry.ts` — static capability registry +
dependency resolution
- `src/capabilities/context.ts` — `CapabilityContext` implementation
(wires to vm-cli tool modules)
- `src/commands/provision/` — provision subcommands (delegates to
capability runner)
- `src/commands/doctor.ts` — health checks with lifecycle-based warnings
- `src/tools/` — system primitives backing `CapabilityContext`

## JSON output protocol

Every command outputs a JSON envelope to stdout:
`{ status, data, errors }`. Progress messages go to stderr. The `--json`
flag enables JSON mode; without it, commands print human-readable output.

## Doctor checks

Each check declares `availableAfter` — the lifecycle phase after which
it should pass. The `--after` flag tells doctor which phase has been
reached. Checks whose phase hasn't been reached are warnings; all others
are errors.

## Build

```bash
bun run build:claw # -> dist/claw (linux-arm64 binary)
```

## Full reference

See [references/vm-cli.md](references/vm-cli.md) for the complete
documentation including the doctor checks table, build/deployment
details, and system primitives.
1 change: 1 addition & 0 deletions .agents/skills/developing-vm-cli/references/vm-cli.md
44 changes: 44 additions & 0 deletions .agents/skills/extending-capabilities/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
name: extending-capabilities
description: "Write and extend VM provisioning capabilities for clawctl. Use when adding new tools to the VM, modifying the provisioning pipeline, writing CapabilityDef modules, or working with lifecycle hooks and CapabilityContext SDK."
---

# Extending Capabilities

Capabilities are the extension mechanism for VM provisioning. Each
capability is a `CapabilityDef` module that declares what it installs,
when it runs (lifecycle phase + hook timing), and what health checks it
provides.

## Key concepts

- **CapabilityDef** — a declarative constant with `name`, `version`,
`hooks` (keyed by lifecycle phase), optional `dependsOn`, and optional
`migrations`.
- **Lifecycle phases** — `provision-system`, `provision-tools`,
`provision-openclaw`, `provision-workspace`, `bootstrap`. Each phase
supports `pre:`, main, and `post:` timing slots.
- **CapabilityContext SDK** — sandboxed interface (`ctx.exec()`,
`ctx.fs`, `ctx.apt`, `ctx.systemd`, `ctx.net`, `ctx.profile`,
`ctx.agentsMd`) that capabilities use for system access. Never import
vm-cli internals directly.
- **Steps** return `ProvisionResult` (`installed` / `unchanged` /
`failed`) and must be idempotent.
- **Doctor checks** are declared via `doctorChecks` on hooks, using
`availableAfter` for lifecycle-aware warnings.
- **State tracking** — `capability-state.json` records installed
versions; version changes trigger migrations or re-provision.

## Adding a new capability

1. Create a module in `packages/capabilities/src/capabilities/`
2. Export a `CapabilityDef` constant
3. Export it from `packages/capabilities/src/index.ts`
4. Register it in `packages/vm-cli/src/capabilities/registry.ts`

## Full reference

See [references/capabilities.md](references/capabilities.md) for the
complete documentation including hook timing, runner mechanics, state
tracking, migrations, core vs optional capabilities, and AGENTS.md
managed sections.
40 changes: 40 additions & 0 deletions .agents/skills/managing-provisioning/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
name: managing-provisioning
description: "Understand and modify the VM provisioning workflow. Use when working on the host-side provisioning sequence, understanding what each phase installs, debugging provisioning failures, or modifying the idempotency/verification flow."
---

# Managing Provisioning

Provisioning installs all system packages, user tools, and OpenClaw
inside the VM. It's driven by the `claw` binary and orchestrated by the
host via `host-core/src/provision.ts`.

## Provisioning sequence

1. Create project directory + git repo on the host
2. Create/start the Lima VM
3. Deploy `claw` binary into the VM
4. `sudo claw provision system` — APT packages, Node.js, systemd linger, Tailscale
5. `claw provision tools` — Homebrew, 1Password CLI, shell profile
6. `claw provision openclaw` — OpenClaw CLI, env vars, gateway stub
7. `claw provision workspace` — skills, workspace files
8. `claw doctor` — verify provisioning
9. `openclaw onboard` — interactive or headless
10. `claw provision bootstrap` — post-onboard hooks (AGENTS.md sections)

## Key properties

- **Idempotent** — each capability step checks current state before
acting; re-running is a fast no-op
- **Capability-driven** — provisioning logic lives in `CapabilityDef`
modules, not in the host or provision commands
- **Verifiable** — `claw doctor` checks health with lifecycle-aware
warnings (`availableAfter`)
- **State-tracked** — `data/capability-state.json` records installed
versions; supports migrations

## Full reference

See [references/vm-provisioning.md](references/vm-provisioning.md) for
the complete documentation including what each phase installs,
verification details, re-running provisioning, and troubleshooting.
45 changes: 45 additions & 0 deletions .agents/skills/understanding-architecture/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
name: understanding-architecture
description: "Understand clawctl's architecture and design decisions. Use when exploring the codebase structure, understanding package responsibilities, learning about the VM backend, mount system, onboarding flow, or making cross-cutting changes."
---

# Understanding the Architecture

`clawctl` is a CLI for creating and managing OpenClaw gateways on macOS.
Each instance is a Lima VM provisioned and managed from the host.

## Package responsibilities

| Package | Role |
| -------------- | --------------------------------------------------- |
| `types` | Shared types, schemas, constants |
| `templates` | Lima config generators (lima-yaml.ts) |
| `capabilities` | Capability definitions + runner + state tracking |
| `host-core` | Host-side library (drivers, provisioning, registry) |
| `cli` | Host CLI (Ink wizard + commands) |
| `vm-cli` | Guest CLI (claw) — runs inside the VM |

## Key design decisions

- **Internal CLI (`claw`)** — compiled TypeScript binary in the VM;
same language on both sides; structured JSON output
- **Capabilities** — self-contained provisioning modules with lifecycle
hooks, dependency resolution, state tracking, and migrations
- **vz backend** — Apple Virtualization.framework for near-native
performance on Apple Silicon
- **virtiofs mounts** — project dir (read-only) + data dir (writable)
survive VM rebuilds
- **Delegate to OpenClaw** — wrap their installer/onboarding, don't
reimplement

## Two modes

- **Interactive wizard** — Ink UI collects config, steps advance
via `onComplete` callbacks
- **Headless** — config-file-driven, no prompts

## Full reference

See [references/architecture.md](references/architecture.md) for the
complete documentation including directory structure, component
relationships, onboarding approach, and error handling.
38 changes: 21 additions & 17 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,16 @@ lifecycle (VM, networking, credentials); OpenClaw manages the agents inside.

## Workspace Structure

Bun workspaces monorepo with five packages:
Bun workspaces monorepo with six packages:

```
packages/
types/ @clawctl/types — Shared types, schemas, constants, pure functions
templates/ @clawctl/templates — Pure script/config generators (string in → string out)
host-core/ @clawctl/host-core — Host-side VM management library (drivers, exec, provision)
cli/ @clawctl/cli — Host CLI (commands + Ink wizard UI)
vm-cli/ @clawctl/vm-cli — Guest CLI (claw) — runs inside the VM
types/ @clawctl/types — Shared types, schemas, constants, pure functions
templates/ @clawctl/templates — Pure script/config generators (string in → string out)
capabilities/ @clawctl/capabilities — Capability definitions, runner, state tracking
host-core/ @clawctl/host-core — Host-side VM management library (drivers, exec, provision)
cli/ @clawctl/cli — Host CLI (commands + Ink wizard UI)
vm-cli/ @clawctl/vm-cli — Guest CLI (claw) — runs inside the VM
```

### Key Directories
Expand All @@ -47,8 +48,9 @@ packages/
- `packages/cli/src/steps/` — wizard step components (each self-contained, calls onComplete)
- `packages/cli/src/components/` — reusable UI components (spinner, progress, log output)
- `packages/host-core/src/` — non-UI logic (drivers, exec, provision, registry)
- `packages/capabilities/src/` — capability definitions (CapabilityDef modules) and runner
- `packages/vm-cli/bin/claw.ts` — guest CLI entry point (compiled to binary, deployed into VM)
- `packages/vm-cli/src/tools/` — typed wrappers for system tools (apt, systemd, node, etc.)
- `packages/vm-cli/src/capabilities/` — capability registry and CapabilityContext implementation
- `packages/vm-cli/src/commands/` — guest CLI commands (provision, doctor, checkpoint)
- `packages/templates/src/` — template generators, one file per generated artifact
- `packages/types/src/` — shared types, schemas, constants
Expand All @@ -69,16 +71,18 @@ packages/

- `claw` is both the agent's management CLI and the VM's installer. All VM-side
setup — system packages, tools, OpenClaw, workspace skills — is provisioned
through `claw` stages. The host deploys the binary and invokes stages; `claw`
does the work inside the VM. See `docs/vm-cli.md` for the full architecture.
- Tool wrappers in `packages/vm-cli/src/tools/` — one module per system tool,
plain functions (not classes). Provision stages import and compose them.
- **Operational functions** (`apt.install()`, `systemd.enable()`) throw on failure.
**Provision functions** (`apt.ensure()`, `homebrew.provision()`) catch errors and
return `ProvisionResult` with `status: "failed"`.
- Provisioning stages are declarative constants, not imperative functions — see
`stages.ts` for the pattern. Doctor checks use lifecycle phases (`availableAfter`)
rather than hardcoded `warn` flags.
through **capabilities**. The host deploys the binary and invokes provisioning
phases; `claw` delegates to the capability runner. See `docs/capabilities.md`
for the extension system and `docs/vm-cli.md` for the guest CLI architecture.
- Capabilities are declared in `packages/capabilities/src/capabilities/` as
`CapabilityDef` modules. Each capability hooks into lifecycle phases and
receives a `CapabilityContext` SDK for system access.
- Remaining tool modules in `packages/vm-cli/src/tools/` (`curl.ts`, `fs.ts`,
`systemd.ts`, `shell-profile.ts`, `openclaw.ts`) back the `CapabilityContext`
implementation — capabilities use them indirectly via the context, not by
direct import.
- Doctor checks are declared on capabilities via `doctorChecks` and use
lifecycle phases (`availableAfter`) rather than hardcoded `warn` flags.
- The `claw` binary is compiled with `bun run build:claw` and deployed into the VM
at `/usr/local/bin/claw` during provisioning.

Expand Down
38 changes: 25 additions & 13 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ are `cli/` (host-side) and `vm-cli/` (guest-side):
packages/
types/ Shared types, schemas, constants
templates/ Lima config generators (lima-yaml.ts)
capabilities/ Capability definitions + runner
src/
capabilities/ Individual capability modules
system-base/ APT packages, Node.js, systemd linger
homebrew/ Homebrew + shell profile
openclaw/ OpenClaw CLI + gateway stub
one-password/ 1Password CLI + skills + AGENTS.md section
checkpoint.ts Checkpoint skill + AGENTS.md section
tailscale.ts Tailscale installer
runner.ts Phase runner (executes resolved hooks)
state.ts State tracking (capability-state.json)
util.ts Hook key parsing
index.ts Public exports
host-core/ Host-side library
src/
drivers/ VM backend abstraction
Expand All @@ -95,22 +108,21 @@ packages/
src/
exec.ts execa wrapper for guest-side commands
output.ts JSON envelope helpers (log, ok, fail)
capabilities/
registry.ts Static capability registry + dependency resolution
context.ts CapabilityContext implementation (wires to vm-cli tools)
commands/
provision/ Declarative stages (system.ts, tools.ts, openclaw.ts) + runner (stages.ts)
provision/ Provision subcommands (delegates to capability runner)
doctor.ts Health checks with lifecycle-based warnings
checkpoint.ts Signal host to commit data changes
tools/ One module per system tool
tools/ System primitives backing CapabilityContext
types.ts ProvisionResult interface
apt.ts apt-get operations
systemd.ts systemctl + loginctl operations
node.ts Node.js via NodeSource
tailscale.ts Tailscale installer
homebrew.ts Homebrew (Linuxbrew)
op-cli.ts 1Password CLI arm64 binary
openclaw.ts OpenClaw CLI + gateway stub
fs.ts File system helpers (ensureLineInFile, ensureDir)
curl.ts Download helpers
shell-profile.ts Login profile management
systemd.ts systemctl + loginctl operations
openclaw.ts OpenClaw CLI queries (isInstalled, version, doctor)
provision-config.ts Provision config reader
```

## Key Design Decisions
Expand All @@ -130,17 +142,17 @@ driver.exec(vmName, "claw doctor --json --after provision-openclaw")
This gives us the same language and type system on both sides of the VM
boundary. Provisioning logic is testable TypeScript, errors are returned
as structured JSON instead of parsed from log output, and every operation
is idempotent by construction (each tool module checks current state
before acting). Doctor checks declare which lifecycle phase they require
is idempotent by construction (capabilities check current state before
acting). Doctor checks declare which lifecycle phase they require
(`availableAfter`), so the host can distinguish expected warnings from
real failures based on how far provisioning has progressed.

The `claw` binary is compiled with `bun run build:claw` (linux-arm64)
and deployed during the provisioning sequence. In development,
`bin/clawctl-dev` auto-builds it before running the host CLI.

See `docs/vm-cli.md` for the full architecture of the guest CLI and its
tool abstraction layer.
See `docs/vm-cli.md` for the guest CLI architecture and
`docs/capabilities.md` for the capability extension system.

### vz virtualization backend

Expand Down
19 changes: 19 additions & 0 deletions docs/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,22 @@ hooks. These integrate with `claw doctor` and follow the same
warning if its phase hasn't been reached yet, an error otherwise.

See `docs/vm-cli.md` for the full doctor checks table.

## Agent Skills (SKILL.md files)

Capabilities can install **Agent Skills** — structured instructions that
coding agents discover and load on demand. Skills follow the
[Agent Skills specification](https://agentskills.io/specification) and
live in the workspace's `.agents/skills/` directory.

A skill is a directory containing a `SKILL.md` file (YAML frontmatter +
Markdown body) plus optional `references/`, `scripts/`, and `assets/`
subdirectories. Agents load only the `name` and `description` at startup;
the full body and referenced files are loaded when the skill is activated.

Existing capability-installed skills:

- **`checkpoint`** (`checkpoint.ts`) — installs the checkpoint skill
into the workspace during `provision-workspace`
- **`one-password`** (`one-password/skill.ts`) — installs the 1Password
skill with wrapper scripts during `provision-tools`
2 changes: 1 addition & 1 deletion docs/cli-wizard-flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Completed fields show with a green checkmark above the current prompt.
**Component**: `src/steps/host-setup.tsx`
**Step indicator**: Step 3/8

This step only appears if Lima was not found in Step 1. It runs `brew install lima` via the `installLima()` function in `src/lib/homebrew.ts`.
This step only appears if Lima was not found in Step 1. It runs `brew install lima` via `installFormula()` from `host-core/src/homebrew.ts`.

**Flow logic**:

Expand Down
11 changes: 9 additions & 2 deletions docs/project-directory.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ When the CLI runs, it creates a project directory with everything needed to mana
<projectDir>/
clawctl.json Instance config (sanitized, no secrets)
data/ Writable persistent mount (survives VM rebuilds)
capability-state.json Tracks installed capability versions
.git/ Git repository
.gitignore Ignores VM images, credentials, .DS_Store
```
Expand Down Expand Up @@ -78,9 +79,15 @@ clawctl create --config config.json

## Provisioning

Provisioning scripts are generated from TypeScript templates and written directly into the VM as ephemeral temp files during bootstrap. They are not persisted in the project directory. See [vm-provisioning.md](./vm-provisioning.md) for details on what is installed.
Provisioning is handled by capabilities — self-contained modules that
declare what they install, when they run, and what health checks they
provide. The host deploys the `claw` binary into the VM and invokes
provisioning phases; capabilities do the work inside the VM.

To add new provisioning steps, modify the template generators in `src/templates/` and recreate the VM.
Installed capability versions are tracked in `data/capability-state.json`.
To add new provisioning steps, write a `CapabilityDef` module. See
[capabilities.md](./capabilities.md) for the extension system and
[vm-provisioning.md](./vm-provisioning.md) for the provisioning sequence.

## data/

Expand Down
5 changes: 3 additions & 2 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ prompt — if it appears stuck, give it time.

### 1Password CLI version

The `op` version is pinned in `src/templates/installers/op-cli.ts`. To update,
change `OP_VERSION` there and recreate the VM.
The `op` version is pinned in
`packages/capabilities/src/capabilities/one-password/op-cli.ts`. To
update, change `OP_VERSION` there, rebuild `claw`, and re-provision.

### General provisioning failures

Expand Down
Loading
Loading