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
6 changes: 6 additions & 0 deletions config/meshloop.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ probe_timeout_seconds = 15
# Optional structured argv run in the attempt worktree after git-diff. Empty = git-diff only.
verify_command = []

# Optional. The planner is routed as a Tier3 task, which only model_tier = "top" fits.
# Name a harness to plan with whatever its tier, or lower the routing tier; not both.
# [planner]
# harness = "claude"
# tier = "Tier2"

[harnesses.grok]
kind = "grok"
executable = "grok"
Expand Down
20 changes: 20 additions & 0 deletions crates/meshloop-adapters/src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,26 @@ impl WorkspacePort for GitWorktreeAdapter {
}
}

fn cherry_pick_range(
&self,
worktree: &Path,
base: &str,
head: &str,
) -> Result<(), WorkspaceError> {
let range = format!("{base}..{head}");
let count = self.run_in(worktree, &["rev-list", "--count", &range])?;
if count.trim() == "0" {
return Ok(());
}
match self.run_in(worktree, &["cherry-pick", &range]) {
Ok(_) => Ok(()),
Err(_) => {
let _ = self.run_in(worktree, &["cherry-pick", "--abort"]);
Err(WorkspaceError::Conflict)
}
}
}

fn branch_exists(&self, branch: &str) -> Result<bool, WorkspaceError> {
match self.run(&["rev-parse", "--verify", branch]) {
Ok(_) => Ok(true),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,46 @@ description: Turn origin-session intent into a Meshloop task graph via meshloop:

You are the **meshloop:origin** supervisor. Do not implement the work.

1. If `MESHLOOP_ORIGIN_SESSION` is unset, run `meshloop doctor --json` and export
`MESHLOOP_ORIGIN_HARNESS` / `MESHLOOP_ORIGIN_SESSION` from the JSON.
2. Write conversation-scoped intent (techniques, scope, exclusions).
3. Invoke the binary (no saga in this skill):
1. Know your origin: your harness name (`claude`, `codex`, `pi`, `grok`, `agy`) and this
session's id. Meshloop takes them from `--origin-harness` / `--origin-session`, or from
`MESHLOOP_ORIGIN_HARNESS` / `MESHLOOP_ORIGIN_SESSION`. `meshloop doctor --json` only
echoes them back (`origin_harness`, `origin_session`); it does not detect them, so pass
them explicitly.
2. Write conversation-scoped intent (techniques, scope, exclusions) to a file.
3. `meshloop plan` starts a planner worker. Follow **Starting workers** below. The command,
with the values at the start of the line replaced:

```text
meshloop plan --objective "<intent>" --intent-file <optional> --json --origin-harness <this-harness> --origin-session <id>
```powershell
$h = "claude"; $s = "0f1e2d3c-session-id"; $d = "C:\Users\me\runs\issue-12"; meshloop plan --objective "Deliver issue 12" --intent-file "$d\intent.md" --config "$d\meshloop.toml" --out "$d\meshloop-plan.json" --json --origin-harness $h --origin-session $s
```

```bash
h=claude; s=0f1e2d3c-session-id; d="/home/me/runs/issue-12"; meshloop plan --objective "Deliver issue 12" --intent-file "$d/intent.md" --config "$d/meshloop.toml" --out "$d/meshloop-plan.json" --json --origin-harness "$h" --origin-session "$s"
```

Equivalent slash: `/meshloop:plan`. MCP: `meshloop_plan`.

4. Show the graph. Then `/meshloop:review-plan`: ask **Accept**, **Decline**, or **Adjust**.
Do not call `meshloop run --accept-plan` until they accept.
5. Never launch a worker in this session. Never use unprefixed `plan` / `planner` tools from other harnesses for this job.
5. Never use unprefixed `plan` / `planner` tools from other harnesses for this job.

## Starting workers

`plan`, `run`, `resume` and `review-plan --adjust` start unattended agents that write
files. Your harness's permission check may refuse to let you run them. That refusal is
correct: do not retry through another command, a script, or a different tool. Either:

- the user runs the command in their own terminal, or
- the user adds a permission rule that allows these Meshloop commands, then asks you to
continue.

When the user runs it, hand over **one line they can paste**:

- Substitute every value. Use absolute paths in double quotes.
- No `<...>` placeholders: PowerShell parses `<` as a redirection operator.
- Match their shell. PowerShell sets values with `$d = "C:\..."; meshloop ...`; POSIX
shells with `d="/..."; meshloop ...`.

You can always run the commands that start nothing: `doctor`, `status`, `inspect`,
`watch` and `roles`. `review-plan --accept|--decline` and `accept` record a person's
decision: run them only after that person answers, and name them with `--as`.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ description: Ask the origin user to accept, decline, or adjust a Meshloop graph.

You are `meshloop:origin`. Do not implement. Do not start workers yet.

If `MESHLOOP_ORIGIN_SESSION` is unset, run `/meshloop:doctor` first.
Pass your origin explicitly (`--origin-harness`, `--origin-session`, or
`MESHLOOP_ORIGIN_HARNESS` / `MESHLOOP_ORIGIN_SESSION`); `/meshloop:doctor` only echoes
them back.

**Ask once, in English**, then wait:

Expand All @@ -16,19 +18,24 @@ If `MESHLOOP_ORIGIN_SESSION` is unset, run `/meshloop:doctor` first.

Treat Portuguese `aceitar` / `recusar` / `ajustar` (and close synonyms) as the
same three intents. Do **not** show CLI flags until they have chosen. Then run
**exactly one**:
**exactly one**, with the values at the start of the line replaced and `--as` naming
the person who answered:

```text
meshloop review-plan --plan meshloop-plan.json --accept --as <identity> --json \
--origin-harness <h> --origin-session <id>
```bash
h=claude; s=0f1e2d3c-session-id; p="/home/me/runs/issue-12/meshloop-plan.json"; meshloop review-plan --plan "$p" --accept --as "Sam" --json --origin-harness "$h" --origin-session "$s"

meshloop review-plan --plan meshloop-plan.json --decline --reason "<why>" --json \
--origin-harness <h> --origin-session <id>
h=claude; s=0f1e2d3c-session-id; p="/home/me/runs/issue-12/meshloop-plan.json"; meshloop review-plan --plan "$p" --decline --reason "Splits issue 12 too finely" --json --origin-harness "$h" --origin-session "$s"

meshloop review-plan --plan meshloop-plan.json --adjust --objective "<changes>" --json \
--origin-harness <h> --origin-session <id>
h=claude; s=0f1e2d3c-session-id; p="/home/me/runs/issue-12/meshloop-plan.json"; meshloop review-plan --plan "$p" --adjust --objective "Merge nodes 2 and 3" --json --origin-harness "$h" --origin-session "$s"
```

Accept and Decline start nothing, so you can run them yourself once the user has
answered. **Adjust runs the planner again**, which starts a worker: your harness may
refuse to let you run it, and that refusal is correct. Do not route around it. Hand the
user one line to paste instead (PowerShell form: `$p = "C:\..."; meshloop review-plan
--plan "$p" ...`), with every value substituted and no `<...>` placeholders, which
PowerShell parses as redirection.

| Reply | Stored | `run` |
|---|---|---|
| Accept | `PlanAccepted` | allowed (no `--accept-plan`) |
Expand Down
59 changes: 47 additions & 12 deletions crates/meshloop-cli/session-bundle/skills/meshloop-run/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,67 @@ description: Execute an accepted Meshloop graph. Supervisor-only origin. Slash /

# /meshloop:run

If `MESHLOOP_ORIGIN_SESSION` is unset, run `/meshloop:doctor` first.
Pass your origin explicitly (`--origin-harness`, `--origin-session`, or
`MESHLOOP_ORIGIN_HARNESS` / `MESHLOOP_ORIGIN_SESSION`); `/meshloop:doctor` only echoes
them back.

**Only after** the user Accepted via `/meshloop:review-plan` (`PlanAccepted`).
If the engine says the plan is not accepted, ask `/meshloop:review-plan` — do
If the engine says the plan is not accepted, ask `/meshloop:review-plan`. Do
**not** add `--accept-plan`.

```text
meshloop run --plan <file> --json --origin-harness <h> --origin-session <id>
`run` starts workers. Follow **Starting workers** below. The command, with the values at
the start of the line replaced (`--detach` returns at once and keeps workers running):

```powershell
$h = "claude"; $s = "0f1e2d3c-session-id"; $d = "C:\Users\me\runs\issue-12"; meshloop run --plan "$d\meshloop-plan.json" --config "$d\meshloop.toml" --detach --json --origin-harness $h --origin-session $s
```

```bash
h=claude; s=0f1e2d3c-session-id; d="/home/me/runs/issue-12"; meshloop run --plan "$d/meshloop-plan.json" --config "$d/meshloop.toml" --detach --json --origin-harness "$h" --origin-session "$s"
```

A **worker executes via direct CLI in an ephemeral git worktree**.
This origin pane must not implement the work. Current branch stays put.

Do not poll `inspect`. Block with `meshloop watch --graph <id> --json` (NDJSON
state changes; last line `{"exit":<reason>,"nodes":[…]}`; exit 0 = needs a human
or completed, 1 = failed/cancelled, 3 = `--timeout`). Then `/meshloop:status` or
`/meshloop:accept`. `--fixture-only` is CI only.
Do not poll `inspect`. Block with `watch`, which starts nothing, so you can run it
yourself (NDJSON state changes; last line such as `{"exit":"awaiting_review","nodes":[2]}`; exit 0 =
needs a human or completed, 1 = failed/cancelled, 3 = `--timeout`):

```bash
meshloop watch --graph issue-12 --config "/home/me/runs/issue-12/meshloop.toml" --json
```

Then `/meshloop:status` or `/meshloop:accept`. `--fixture-only` is CI only.

`--accept-plan` on `run` is a debug shortcut that skips the 3-way question.
Do not use it from this skill.

If the engine says the graph already exists / FailedTerminal, do **not** invent a
new `graph_id`. The operator can re-run this accepted plan with:
new `graph_id`. Re-run the accepted plan with `resume --restart` (it starts workers,
so the same rules apply), or `run --plan ... --reset`. `--restart` and `--retry` are
exclusive:

```text
meshloop resume --restart --json --origin-harness <h> --origin-session <id>
```bash
h=claude; s=0f1e2d3c-session-id; d="/home/me/runs/issue-12"; meshloop resume --restart --config "$d/meshloop.toml" --json --origin-harness "$h" --origin-session "$s"
```

or `meshloop run --plan <file> --reset`. `--restart` and `--retry` are exclusive.
## Starting workers

`plan`, `run`, `resume` and `review-plan --adjust` start unattended agents that write
files. Your harness's permission check may refuse to let you run them. That refusal is
correct: do not retry through another command, a script, or a different tool. Either:

- the user runs the command in their own terminal, or
- the user adds a permission rule that allows these Meshloop commands, then asks you to
continue.

When the user runs it, hand over **one line they can paste**:

- Substitute every value. Use absolute paths in double quotes.
- No `<...>` placeholders: PowerShell parses `<` as a redirection operator.
- Match their shell. PowerShell sets values with `$d = "C:\..."; meshloop ...`; POSIX
shells with `d="/..."; meshloop ...`.

You can always run the commands that start nothing: `doctor`, `status`, `inspect`,
`watch` and `roles`. `review-plan --accept|--decline` and `accept` record a person's
decision: run them only after that person answers, and name them with `--as`.
5 changes: 4 additions & 1 deletion crates/meshloop-cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ pub enum Command {
graph: String,
into: String,
accept_integrate: bool,
deliverable: Option<String>,
config: Option<PathBuf>,
db: Option<PathBuf>,
worktree_base: Option<PathBuf>,
Expand Down Expand Up @@ -266,6 +267,7 @@ fn verb_flags(verb: &str) -> Option<&'static [(bool, &'static str)]> {
(true, "--graph"),
(true, "--into"),
(false, "--accept-integrate"),
(true, "--deliverable"),
(true, "--config"),
(true, "--db"),
(true, "--worktree-base"),
Expand Down Expand Up @@ -528,6 +530,7 @@ fn parse_command(args: &[String]) -> Result<Command, String> {
graph,
into,
accept_integrate: has_flag(rest, "--accept-integrate"),
deliverable: flag_value(rest, "--deliverable"),
config: flag_value(rest, "--config").map(PathBuf::from),
db: flag_value(rest, "--db").map(PathBuf::from),
worktree_base: flag_value(rest, "--worktree-base").map(PathBuf::from),
Expand Down Expand Up @@ -671,7 +674,7 @@ mod tests {
"inspect --session-id s --graph g --task 1 --config c --db d --attempts",
"watch --session-id s --graph g --interval 2 --timeout 9 --config c --db d",
"accept --task 1 --as me --graph g --config c --db d --worktree-base w",
"integrate --graph g --into main --accept-integrate --config c --db d --worktree-base w",
"integrate --graph g --into main --accept-integrate --deliverable t --config c --db d --worktree-base w",
"orchestrate --task 1 --graph g --config c --db d --worktree-base w --model-a a --model-b b --fixture-only",
"bundle --dest d --gitignore",
"ast-skeleton --path p",
Expand Down
10 changes: 8 additions & 2 deletions crates/meshloop-cli/src/compose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use meshloop_engine::agent::AgentSpec;
use meshloop_engine::origin::Origin;
use meshloop_engine::ports::{HarnessCapabilities, HarnessHandle, HarnessOutcome, StoreError};
use meshloop_engine::router::Candidate;
use meshloop_engine::run_loop::RunLimits;
use meshloop_engine::run_loop::{PlannerSelection, RunLimits};

use crate::config::{Config, HarnessConfig, Limits, resolve_executable};

Expand Down Expand Up @@ -79,9 +79,10 @@ pub struct Composed {
pub limits: RunLimits,
pub verify_command: Vec<String>,
pub worktree_base: PathBuf,
pub planner: PlannerSelection,
}

fn parse_model_tier(s: &str) -> ModelCapabilityTier {
pub(crate) fn parse_model_tier(s: &str) -> ModelCapabilityTier {
match s {
"top" => ModelCapabilityTier::TopTier,
"mid" => ModelCapabilityTier::MidTier,
Expand Down Expand Up @@ -177,6 +178,11 @@ pub fn compose(req: ComposeRequest<'_>) -> Result<Composed, String> {
.clamped(),
verify_command: req.config.verify.verify_command.clone(),
worktree_base: wt,
planner: req
.config
.planner
.selection()
.map_err(|e| format!("{e:?}"))?,
})
}

Expand Down
Loading
Loading