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
42 changes: 42 additions & 0 deletions .changeset/cutover-published-engine-014-rehome-harness.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
'@smooai/smooth': patch
---

Cut smooth over to the published `smooai-smooth-operator-core` v0.14.0 (crates.io); re-home the th-code harness into smooth's own crates

This is the final PR of the engine-decouple program (SMOODEV-1790, PR 4/4). The
engine `smooai-smooth-operator-core` is now published on crates.io at `0.14.0` —
a clean, GENERIC agent engine with the `th code` coding harness REMOVED.
Previously smooth depended on the engine via a git rev (`bb9a256`) that still
carried the harness, which is why it kept building.

- **Engine dep switched to crates.io 0.14.0.** Root `Cargo.toml`:
`smooth-operator = { git = …, rev = "bb9a256…" }` →
`smooth-operator = { version = "0.14.0", package = "smooai-smooth-operator-core" }`.
The dep KEY stays `smooth-operator` so the `use smooth_operator::…` imports for
the generic engine API are unchanged. `Cargo.lock` now resolves the engine from
`registry+https://github.com/rust-lang/crates.io-index` (checksum-pinned), not a
git source — the git-rev bridge is gone.

- **New `smooth-cast` crate** re-homes the bits the engine dropped, built on the
engine's generic public API (`Agent`/`ProviderRegistry`/`ToolRegistry`/generic
`Cast`/`OperatorRole`/`Clearance`):
- `coding_workflow` — the `th code` single-agent outer loop
(`run_coding_workflow`, `task_text_has_cleanup_intent`, …).
- `skills` — skill discovery (`discover`, `SkillScope`, `SkillSource`, `Skill`)
plus the built-in `create-skill` skill.
- `cast` — the four coding-harness cast roles the generic engine no longer ships
(`fixer`, `oracle`, `chief`, `intent_classifier`), and a `cast::builtin()` that
returns them on top of the engine's generic built-in roles. All moved tests came
with the code.

- **Consumers repointed** to `smooth-cast`: `smooth-operative` (coding_workflow +
`fixer` role resolution), `smooth-code` (skills + `chief`/`intent_classifier`
routing), `smooth-cli` (skills + `--agent` role resolution), `smooth-bigsmooth`
(skills + session auto-naming). Every site that did `Cast::builtin().get("fixer"|
"oracle"|"chief"|"intent_classifier")` now uses `smooth_cast::cast::builtin()`.

- The Big-Smooth reporter hooks the engine also dropped stay deleted — verified
zero smooth consumers (`with_reporter`/`BigSmoothReporter`/`ReporterEvent`/
`report_to_bigsmooth`/the `bigsmooth` engine feature). smooth's own
`smooth-bigsmooth` gRPC crate is unrelated and untouched.
24 changes: 22 additions & 2 deletions Cargo.lock

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

21 changes: 14 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -178,18 +178,25 @@ prost-types = "0.13"
# relevant to the bind-mount silent drop tracked in th-dd0cef).
microsandbox = "0.4"

# Published agent engine (github.com/SmooAI/smooth-operator-core).
# Published agent engine (crates.io: smooai-smooth-operator-core).
# SMOODEV-1787 (PR 1/4, dual-engine collapse): smooth consumes the public
# `smooai-smooth-operator-core` engine instead of an in-tree copy. The in-tree
# `crates/smooth-operator` copy was deleted. The dep KEY stays `smooth-operator`
# and the lib is package-aliased back to `smooth_operator`, so the ~12 consumers'
# `use smooth_operator::…` imports keep working unchanged.
# `use smooth_operator::…` imports for the GENERIC engine API keep working
# unchanged.
#
# Rev-pinned git dep (NOT a sibling path dep): a `path = "../smooth-operator-core/…"`
# form only resolves on a dev laptop and breaks every CI `cargo metadata` run —
# the exact failure SMOODEV-1464 hit with client-shared (see that dep below).
# Bump the rev when the engine changes.
smooth-operator = { git = "https://github.com/SmooAI/smooth-operator-core.git", rev = "bb9a2565f0187fbd860240868c5775bd1205764d", package = "smooai-smooth-operator-core" }
# SMOODEV-1790 (PR 4/4, final cutover): switched from the rev-pinned git dep on
# the OLD engine (rev bb9a256, which still carried the th-code harness) to the
# published crates.io release `0.14.0` — a clean GENERIC engine with the harness
# REMOVED. The harness bits the engine dropped (the coding workflow, skill
# discovery, and the fixer/oracle/chief/intent_classifier cast roles) now live
# in the smooth-owned `smooth-cast` crate below, built on the engine's generic
# public API.
smooth-operator = { version = "0.14.0", package = "smooai-smooth-operator-core" }
# smooth-owned coding-harness extensions to the generic engine (re-homed from
# the engine when it went generic at 0.14.0). See crates/smooth-cast.
smooth-cast = { version = "0.13.7", path = "crates/smooth-cast", package = "smooai-smooth-cast" }
smooth-bigsmooth = { version = "0.13.7", path = "crates/smooth-bigsmooth", package = "smooai-smooth-bigsmooth" }
smooth-policy = { path = "crates/smooth-policy", version = "0.13.7", package = "smooai-smooth-policy" }
smooth-web = { version = "0.13.7", path = "crates/smooth-web", package = "smooai-smooth-web" }
Expand Down
2 changes: 2 additions & 0 deletions crates/smooth-bigsmooth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ direct-sandbox = ["smooth-bootstrap-bill/server"]
smooth-pearls.workspace = true
smooth-bootstrap-bill = { workspace = true, default-features = false }
smooth-operator.workspace = true
# skills discovery + the smooth cast roles (re-homed from the engine at 0.14.0)
smooth-cast.workspace = true
smooth-code = { path = "../smooth-code", package = "smooai-smooth-code" }
smooth-policy.workspace = true
smooth-web = { path = "../smooth-web", package = "smooai-smooth-web" }
Expand Down
2 changes: 1 addition & 1 deletion crates/smooth-bigsmooth/src/chat_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ impl Tool for TeammateSpawnTool {
"extra_prompt": { "type": "string", "description": "Optional extra instruction appended after the context_brief. Use this for fine-grained constraints (e.g. 'use the Rust 2021 edition', 'don't touch the migrations directory')." },
"budget_usd": { "type": "number", "description": "Optional cost cap in USD for this dispatch." },
"working_dir": { "type": "string", "description": "Working directory for the teammate's sandbox. Pass the most specific absolute path that scopes the work — e.g. for 'clone repo X to ~/dev/foo/X' pass `~/dev/foo`. Never pass a directory as broad as `~` or `/`; the runner can stall enumerating that much filesystem." },
"role": { "type": "string", "description": "Optional cast role to spawn under (e.g. `fixer`, `mapper`, `oracle`, `heckler` — see smooth-operator/src/cast). Affects permissions, prompt, and routing slot." },
"role": { "type": "string", "description": "Optional cast role to spawn under (e.g. `fixer`, `mapper`, `oracle`, `heckler` — resolved via smooth_cast::cast::builtin()). Affects permissions, prompt, and routing slot." },
"model": { "type": "string", "description": "DO NOT SET unless you have a specific reason. Default = role's slot (smooth-coding for `fixer`) which is the best balance of speed and tool-call reliability. Avoid `smooth-fast-gemini` — it can't reliably emit native tool calls and will wedge the runner. `smooth-reasoning` is for genuinely hard problems only." }
}
}),
Expand Down
5 changes: 3 additions & 2 deletions crates/smooth-bigsmooth/src/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,8 +603,9 @@ fn registered_tool_names() -> Vec<String> {
}

/// Read-only subset — what reasoning roles (oracle, mapper, heckler) get.
/// Must stay in sync with `read_only_tools()` in
/// `crates/smooth-operator/src/cast/mod.rs`.
/// Must stay in sync with `read_only_tools()` in the engine's
/// `cast/mod.rs` (mapper/heckler) and the smooth re-homed copy in
/// `crates/smooth-cast/src/cast.rs` (oracle).
fn read_only_tool_names() -> Vec<String> {
vec![
"read_file".into(),
Expand Down
4 changes: 2 additions & 2 deletions crates/smooth-bigsmooth/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3550,7 +3550,7 @@ fn extract_skill_allowed_hosts(message: &str, workspace: &str) -> Vec<String> {
return Vec::new();
}
let workspace_path = std::path::PathBuf::from(workspace);
let skills = smooth_operator::skills::discover(&workspace_path);
let skills = smooth_cast::skills::discover(&workspace_path);
let Some(skill) = skills.into_iter().find(|s| s.name == name) else {
tracing::warn!(skill_name = name, "skill named in message header but not found in discovery — no pre-grant");
return Vec::new();
Expand Down Expand Up @@ -4570,7 +4570,7 @@ async fn post_chat_message_stream_handler(
async fn auto_name_session(user_prompt: &str) -> Option<String> {
let providers_path = dirs_next::home_dir()?.join(".smooth/providers.json");
let registry = ProviderRegistry::load_from_file(&providers_path).ok()?;
let cast = smooth_operator::cast::Cast::builtin();
let cast = smooth_cast::cast::builtin();
let agent = cast.get("tagger")?;
let config = registry.llm_config_for(agent.slot).ok()?;
let llm = smooth_operator::llm::LlmClient::new(config);
Expand Down
31 changes: 31 additions & 0 deletions crates/smooth-cast/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "smooai-smooth-cast"
version = "0.13.7"
edition.workspace = true
license.workspace = true
repository.workspace = true
description = "Smooth coding-harness extensions to the smooth-operator engine — the th-code coding workflow, skill discovery, and the harness-specific cast roles (fixer/oracle/chief/intent_classifier) that the published generic engine no longer ships."

[lib]
name = "smooth_cast"
path = "src/lib.rs"

[dependencies]
# The published generic engine. smooth-cast re-homes the coding-harness
# bits the engine dropped at 0.14.0 and builds the custom cast roles on
# the engine's generic Cast/OperatorRole/Clearance public API.
smooth-operator.workspace = true

anyhow.workspace = true
serde = { workspace = true }
serde_json.workspace = true
serde_yml.workspace = true
dirs-next.workspace = true
tokio.workspace = true
tracing.workspace = true

[dev-dependencies]
tempfile.workspace = true

[lints]
workspace = true
109 changes: 109 additions & 0 deletions crates/smooth-cast/builtin-skills/create-skill/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
name: create-skill
description: Author a new skill (SKILL.md) for Smooth. Asks clarifying questions, drafts the frontmatter + body, writes the file to the user's chosen location, and offers a test invocation.
triggers:
- make a skill
- create a skill
- add a skill
- save this as a skill
- new skill
- author a skill
scope: host
allowed_tools:
- read_file
- write_file
- edit_file
- list_files
- bash
---

# create-skill

The user wants to add a reusable recipe to their Smooth setup. Your job: turn a description of what the recipe should do into a well-formed `SKILL.md` file at the right path.

## Process

### 1. Clarify (if needed)

If the user's request is vague — e.g. "make a skill for git stuff" — ask ONE question to narrow it:

- "What should this skill do specifically? Concrete steps help."

Skip clarifying if the request is concrete enough on its own ("make a skill that adds a movie to my smoo-hub watchlist using the api at smoo-hub:8787" — that's actionable).

### 2. Decide scope: project or user

Ask if you don't know:

- **Project scope** (`<workspace>/.smooth/skills/<name>/SKILL.md`) — the skill is tied to this codebase. Other workspaces don't see it. Commit it to the repo so teammates get it too.
- **User scope** (`~/.smooth/skills/<name>/SKILL.md`) — the skill applies to every Smooth dispatch you ever do, in any workspace. Personal.

Default to user scope if the user just says "save it" without specifying.

### 3. Pick a name

Lowercase, hyphenated, descriptive. `add-show`, `format-rust`, `sync-to-s3`. The directory name and the `name:` frontmatter must match.

### 4. Determine the scope: sandbox or host

- `sandbox` (default) — the skill runs inside the microVM. Use when the skill only touches `/workspace`, runs build/test commands, edits source code, or needs nothing outside the sandbox.
- `host` — the skill bypasses the microVM and runs in Big Smooth's process directly. Use ONLY for genuine host-needing cases: `scp` to a local-network host, `sips` / macOS-specific tools, AWS SSO browser flows, Photos.app integration.

**Network alone is NEVER a reason for `host`.** Network access from the sandbox is handled by `allowed_hosts` below.

### 5. Determine `allowed_hosts`

If the skill needs to reach a host the default Wonk policy doesn't allow (`llm.smoo.ai` is the only default), list those hosts here. Examples:

- `smoo-hub` — LAN/tailscale-only personal server
- `api.tvmaze.com` — public API
- `*.azureedge.net` — wildcard for a CDN family

Be specific. Don't list `*` or "all"; users won't accept that grant.

### 6. Determine `allowed_tools`

Optional. If left empty, the skill inherits the agent's full toolset. Use to RESTRICT (not expand) — e.g. a read-only summarize skill might say `allowed_tools: [read_file, list_files, grep]`.

### 7. Write the SKILL.md body

The body is what the agent reads when the skill is invoked. Make it:

- **Short.** 30–80 lines for most skills. A long skill that the model has to wade through is worse than no skill.
- **Step-by-step.** Numbered list of what to do, in order. The model will follow it literally.
- **Concrete on commands.** Show the exact `curl`, `bash`, or tool invocation. Not "make an API call" but `curl -X POST http://smoo-hub:8787/api/shows -H 'Content-Type: application/json' -d '{...}'`.
- **Explicit on inputs.** Name what the user will provide (title, status, etc.) and what defaults you'll assume when they're missing.

Optional sections worth including:

- `## Inputs` — what the user typically provides
- `## Outputs` — what the user will see / what gets created
- `## Failure modes` — what to do when X is missing, Y returns 404, etc.

### 8. Write the file

For project scope:
```bash
mkdir -p .smooth/skills/<name>
# write SKILL.md
```

For user scope:
```bash
mkdir -p ~/.smooth/skills/<name>
# write SKILL.md
```

Then run `th skills list` to confirm the skill is discovered.

### 9. (Optional) Test it

If the user wants, offer to invoke the skill once with a sample input. Just suggest the invocation phrasing — don't auto-invoke unless they ask.

## Output

When done, reply with ONE sentence:

> "Created `<name>` at `<path>`. Run `th skills show <name>` to inspect or invoke by saying something matching: `<one trigger phrase>`."

That's it. No essay. The diff is the artifact; the sentence confirms it landed.
Loading
Loading