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
41 changes: 41 additions & 0 deletions .changeset/microvm-doc-purge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
"@smooai/smooth": patch
---

Fix the broken dev loop and purge the microVM-era leftovers that were misleading
agents and humans reading this repo (th-e827ba).

- **`pnpm install:th` was broken — it exited 101 for everyone.** It ran `cargo
install --path crates/smooth-operative`, a directory deleted with the microVM
stack. `th` itself installs first, so the failure landed at the end: the
binary looked fine while the documented dev loop (CLAUDE.md §2) returned
non-zero, failing any hook or CI step gated on it. It now installs
`smooth-daemon` — what `th daemon` / `th up` actually need resolvable on PATH,
since `th` deliberately doesn't link the daemon in. Same fix for
`install:th:full`. Verified by running to completion.
- **Deleted `scripts/bench.sh`** — a wrapper around `smooai-smooth-bench`, also
deleted with the microVM stack.
- **`CLAUDE.md` §1/§4 rewritten against the real tree.** The workspace structure
and "Key Crates" list documented six crates that no longer exist
(`smooth-bigsmooth`, `smooth-narc`, `smooth-scribe`, `smooth-archivist`,
`smooth-operative`, and `smooth-operator` — which now lives in its own repo)
while omitting seven that do. §4's module table, dispatch description, and
security architecture all described the deleted `smooth-bigsmooth` and are now
written against `smooth-daemon` (permission hook → Narc → kernel sandbox).
- **`smooth-goalie` documented as it is now**: not the in-VM Wonk-delegating
network proxy, but the daemon's egress boundary via `AuditLogger` +
`run_proxy_local`.
- **Broken paths fixed**: `crates/smooth-cli/src/api/` (doesn't exist) →
`src/smooai/`; `th operators` → `th operatives`; the `th cache` /
`~/.smooth/project-cache` docs described a command that no longer exists.
- **`rusqlite` 0.32 → 0.40.** The pin existed to unify `libsqlite3-sys` with
microsandbox's sea-orm→sqlx tree; microsandbox is gone and rusqlite is now the
only crate linking sqlite3. No API changes needed.
- **User-facing strings corrected**: `th code` cold-start printed "starting
Safehouse microVM" and "cast online (wonk · goalie · narc · scribe · archivist
· diver · groove)"; boot failures blamed a "Safehouse microVM" that hasn't
existed for weeks.
- Stale `//!` doc comments and crate manifest descriptions swept across
`smooth-goalie`, `smooth-tools`, `smooth-policy`, `smooth-diver`,
`smooth-daemon`, and `smooth-cli`, plus the README workspace tree and the dead
microsandbox image / project-cache sections.
10 changes: 6 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,12 @@ jobs:

- name: Install macOS build deps
if: runner.os == 'macOS'
# protobuf: smooth-narc's prost build.rs needs `protoc` (the
# Linux step above installs it via apt; macOS runners have
# neither protoc nor it on PATH, so the cross-platform binary
# build failed with "Could not find protoc"). Pearl th-14bddf.
# protobuf: originally for smooth-narc's prost build.rs, which
# failed the macOS cross-platform build with "Could not find
# protoc" (pearl th-14bddf). That crate went with the microVM
# stack (2026-07/th-f4a801) and no build.rs in the tree shells
# out to protoc today — kept as cheap insurance because a
# release build is the worst place to discover otherwise.
run: brew install protobuf

- name: Install pnpm
Expand Down
167 changes: 89 additions & 78 deletions CLAUDE.md

Large diffs are not rendered by default.

67 changes: 39 additions & 28 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 15 additions & 15 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
[workspace]
resolver = "2"
members = ["crates/*"]
exclude = ["crates/smooth-bigsmooth/tests/fixtures"]

[workspace.package]
version = "0.22.0"
Expand Down Expand Up @@ -36,12 +35,13 @@ axum-extra = { version = "0.10", features = ["typed-header"] }
tower = "0.5"
tower-http = { version = "0.6", features = ["cors", "fs", "trace"] }

# Database — pinned to 0.32 so `libsqlite3-sys 0.30` is the single version in
# the tree. `microsandbox` (via sea-orm → sqlx → libsqlite3-sys 0.30) and
# `rusqlite` both link the `sqlite3` native library, so their versions must
# unify. rusqlite 0.32 uses the same APIs we care about (Connection, params!,
# query, prepare, Row, types::ToSql).
rusqlite = { version = "0.32", features = ["bundled"] }
# Database — `smooth-daemon`'s durable local storage (schedules, operator
# state). `bundled` compiles SQLite into the binary, so there is no system
# `sqlite3` to match. rusqlite is the only crate in the tree that links it
# (`cargo tree -i libsqlite3-sys`); the old 0.32 pin existed to unify with
# microsandbox's sea-orm → sqlx → libsqlite3-sys 0.30, and died with the
# microVM stack (2026-07, pearl th-f4a801).
rusqlite = { version = "0.40", features = ["bundled"] }
# SMOODEV-1468: sync Postgres checkpoint store (smooth-operator `postgres` feature)
# + testcontainers-backed integration tests. Sync `postgres` crate (not async
# sqlx) because the CheckpointStore trait is synchronous, mirroring rusqlite.
Expand Down Expand Up @@ -69,15 +69,15 @@ serde_json = "1"
serde_yml = "0.0.12"

# HTTP client
# Use rustls-tls-webpki-roots so the crate ships its own CA bundle (no system
# certs needed). This is critical for smooth-operative running inside
# alpine microVMs which don't have ca-certificates installed by default.
# Use rustls-tls-webpki-roots so the crate ships its own CA bundle rather than
# reading the system trust store — `th` is distributed as a standalone binary
# and must work on hosts with no `ca-certificates` installed.
#
# `hickory-dns` enables a pure-Rust DNS resolver instead of getaddrinfo. This
# is critical for the in-VM runner because alpine's musl getaddrinfo has been
# observed to return EAI_AGAIN against microsandbox's intercepted DNS — the
# pure-Rust hickory resolver reads /etc/resolv.conf and sends UDP queries
# directly, which the microsandbox DNS interceptor handles correctly.
# `hickory-dns` swaps getaddrinfo for a pure-Rust resolver that reads
# /etc/resolv.conf and sends UDP queries itself. Originally needed because
# alpine musl's getaddrinfo returned EAI_AGAIN against the microVM's
# intercepted DNS (that stack is gone, 2026-07/th-f4a801); kept because it
# keeps resolution independent of the host's libc and NSS config.
reqwest = { version = "0.12", default-features = false, features = ["json", "stream", "rustls-tls-webpki-roots", "charset", "http2", "hickory-dns"] }

# File search
Expand Down
72 changes: 24 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,8 @@ See [`docs/extending.md`](docs/extending.md) for the full guide.
### Run a pearl (`th run`)

Dispatch a pearl (or ad-hoc prompt) to a Smooth operative. Big Smooth
(`th up`) execs the operative as a host subprocess against your current
directory and streams agent events to stdout.
(`th up`) runs the agent turn against your current directory and streams
agent events to stdout.

```bash
# First ready pearl
Expand All @@ -323,39 +323,13 @@ th operatives list
th operatives kill <operator-id>
```

> The `--image`, `--memory-mb`, and `--keep-alive` flags (and the
> `smooai/smooth-operative` microVM image) went away with the microVM
> stack, 2026-07 (pearl `th-f4a801`). The operative now runs directly on
> the host and uses your real toolchain — no per-VM image or cache mount.

Build locally:

```bash
scripts/build-smooth-operative-image.sh
```

Override via `--image` or `SMOOTH_OPERATIVE_IMAGE` env if you want a
custom variant (e.g. a version pinned for CI reproducibility).

**Microsandbox image resolution.** Locally-built images live in
your Docker Desktop image store; `microsandbox` pulls from registries
by default, so if its pull can't see your local build, push it
first (`docker push smooai/smooth-operative:0.2.0`) or set
`SMOOTH_OPERATIVE_IMAGE` to something microsandbox can reach.

**Project cache.** Each workspace path hashes to its own cache,
mounted at `/opt/smooth/cache` inside the VM. Subsequent runs on the
same repo share mise installs + language stores (pnpm-store, cargo
registry, uv cache, etc.). Backed by a first-class microsandbox
Volume by default (`~/.microsandbox/volumes/smooth-cache-<key>/`);
set `SMOOTH_USE_VOLUMES=0` to fall back to the legacy bind-mount
(`~/.smooth/project-cache/<key>/`). Manage with:

```bash
th cache list # shows entries from both backends, tagged
th cache prune --older-than 30 # evict caches idle > N days
th cache clear /path/to/project # remove entry for a specific workspace
```
> The `--image`, `--memory-mb`, and `--keep-alive` flags, the
> `smooai/smooth-operative` microVM image, the image-build script, and
> the per-workspace VM cache (`th cache`) all went away with the microVM
> stack, 2026-07 (pearl `th-f4a801`). Work now runs directly on the host
> against your real toolchain — no image, no cache mount. `bash` tool
> calls are confined by the kernel OS sandbox and egress goes through the
> allowlist proxy.

### Background service

Expand Down Expand Up @@ -509,24 +483,26 @@ See [`docs/extending.md`](docs/extending.md) and [`SECURITY.md`](SECURITY.md).
```
smooth/
├── crates/
│ ├── smooth-cli/ # Binary — clap CLI, the `th` entry point
│ ├── smooth-bigsmooth/ # Library — orchestrator, policy gen, session mgmt, in-process dispatch
│ ├── smooth-operator/ # Library — Rust-native AI agent framework
│ ├── smooth-operative/ # Binary — agent loop for a dispatched pearl (host subprocess)
│ ├── smooth-cli/ # Binary `th` — clap CLI, the entry point
│ ├── smooth-daemon/ # Binary + lib — Big Smooth, the always-on agent daemon
│ ├── smooth-tools/ # Library — agent tools + the kernel OS sandbox
│ ├── smooth-policy/ # Library — shared policy types, TOML parsing
│ ├── smooth-narc/ # Library — tool surveillance + secret detection
│ ├── smooth-scribe/ # Library — structured logging
│ # (removed 2026-07, pearl th-f4a801: smooth-bootstrap-bill, smooth-wonk,
│ # smooth-goalie, smooth-host-stub, smooth-credential-helper — see git history)
│ ├── smooth-archivist/ # Library — central log aggregator
│ ├── smooth-goalie/ # Library + bin — HTTP forward proxy (egress boundary)
│ ├── smooth-pearls/ # Library — Dolt-backed pearl tracker
│ ├── smooth-plugin/ # Library — CLI-wrapper plugin manifests
│ ├── smooth-cast/ # Library — coding-harness cast roles, skills, workflow
│ ├── smooth-code/ # Library — `th code` ratatui coding TUI
│ ├── smooth-diver/ # Library — pearl lifecycle manager + Jira sync
│ ├── smooth-tunnel/ # Library — th.smoo.ai reverse-tunnel client
│ ├── smooth-bench/ # Binary — coding-benchmark harness (aider-polyglot, SWE-bench, …)
│ ├── smooth-code/ # Library — ratatui terminal dashboard
│ ├── smooth-tmux/ # Library — tmux driver (supervises Claude Code)
│ ├── smooth-api-client/ # Library — generated api.smoo.ai client + auth
│ └── smooth-web/ # Library — embedded Vite SPA
│ └── web/ # React + Vite source
│ # The agent engine `smooth-operator` is NOT in this workspace — it lives in
│ # the separate SmooAI/smooth-operator repo and is consumed as a dependency.
│ # Removed 2026-07 (pearl th-f4a801, see git history): smooth-bigsmooth,
│ # smooth-operative, smooth-narc, smooth-scribe, smooth-archivist,
│ # smooth-wonk, smooth-bootstrap-bill, smooth-host-stub,
│ # smooth-credential-helper.
├── Cargo.toml # Workspace root
├── rustfmt.toml # Format config
└── install.sh # Curl installer
Expand Down
22 changes: 11 additions & 11 deletions crates/smooth-cli/src/boot_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
//! Pearl th-7840d8 — replaces the bare `println!("Starting Smooth...")`
//! cold-boot line (and the matching path inside `th up`) with a
//! per-step spinner cascade so the user can see what's happening
//! while the Safehouse microVM and in-VM cast services come up.
//! while Big Smooth (the daemon) comes up.
//!
//! Visuals:
//!
//! ```text
//! ✻ Smooth booting
//! ⠋ starting Safehouse microVM
//! ⠋ cast online (wonk · goalie · narc · scribe · archivist · diver · groove)
//! ⠋ operative pool warm
//! ⠋ starting Big Smooth
//! ⠋ dolt store online
//! ⠋ dispatch ready
//! ⠋ health check…
//! ```
//!
Expand Down Expand Up @@ -160,7 +160,7 @@ mod tests {
#[test]
fn step_ok_completes_cleanly() {
let ind = BootIndicator::new();
let step = ind.step("starting Safehouse microVM");
let step = ind.step("starting Big Smooth");
// No real work — just check the lifecycle.
step.ok();
ind.finish();
Expand All @@ -179,9 +179,9 @@ mod tests {
#[test]
fn multiple_steps_finalize_in_arbitrary_order() {
let ind = BootIndicator::new();
let s1 = ind.step("starting Safehouse microVM");
let s2 = ind.step("cast online (wonk · goalie · narc · scribe · archivist · diver · groove)");
let s3 = ind.step("operative pool warm");
let s1 = ind.step("starting Big Smooth");
let s2 = ind.step("dolt store online");
let s3 = ind.step("dispatch ready");
let s4 = ind.step("health check");

// Finalize out of order to confirm the API doesn't require
Expand All @@ -198,8 +198,8 @@ mod tests {
#[test]
fn step_update_is_safe() {
let ind = BootIndicator::new();
let step = ind.step("cast online");
step.update("cast online (3/7 services up)");
let step = ind.step("dolt store online");
step.update("dolt store online (pearls)");
step.ok();
ind.finish();
}
Expand All @@ -208,7 +208,7 @@ mod tests {
#[test]
fn indicator_drops_without_finish_call() {
let ind = BootIndicator::new();
let step = ind.step("starting Safehouse microVM");
let step = ind.step("starting Big Smooth");
step.ok();
// No ind.finish() — Drop should handle it.
}
Expand Down
Loading
Loading