Skip to content
Open
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
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
Open Pstack lands on green: Mergify merges a ready PR to main once verify and exact-head live-gate pass and no review thread is unresolved, and a workflow resolves Unfret's own threads. A PR that touches `.github/` or the Mergify config also waits for Unfret, and workflow changes require operator queueing.
This port applies the Cursor → Claude Code substitutions in skill bodies. Earlier drafts left them flagged; this revision resolves them. A later pass added a Codex build that shares the same skills; see [Codex port](#codex-port) below.

## Unreleased

**Muse Wonder Full 1.0 lanes.** The model catalog registers `muse:muse-wonder-full-1.0` as an optional family with efforts `low` to `max` and a default of `max`, so `/setup-pstack` can place it in a role or panel. Muse lanes keep the external runner from every parent, and a Muse writer still needs `muse writer sandbox: full-access`. The Muse preflight also passes a signed-in `muse usage` that prints `No usage data (server_sent_no_usage)`, with the evidence `subscription-no-usage-data`; measured with Muse Code 1.4.14, that output proves the login, and the model call still checks the allowance. Default roles and panels are unchanged.

## 1.21.0 adds Grok as a parent harness

Open Pstack 1.21.0 keeps the Cursor pstack 0.15.36 sync. Default roles and panels are unchanged.
Expand Down
5 changes: 3 additions & 2 deletions plugins/pstack/skills/poteto-mode/references/model-catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Model and provider facts for [`provider-dispatch.md`](provider-dispatch.md), whi
| gemini-3.8-flash | Gemini 3.8 Flash (Antigravity) | agy | gemini-3.8-flash | high | low medium high | - | optional | - |
| composer-2.5 | Composer 2.5 (Cursor) | cursor | composer-2.5 | default | default | - | optional | - |
| gemini-3.7-flash | Gemini 3.7 Flash (Cursor) | cursor | gemini-3.7-flash | high | low medium high | - | optional | - |
| muse-wonder-full-1.0 | Muse Wonder Full 1.0 | muse | muse-wonder-full-1.0 | max | low medium high xhigh max | - | optional | - |

A family is `default` when a role default names it and `optional` otherwise. A Claude-native agent exists for each selectable effort of a Claude family.

Expand Down Expand Up @@ -224,13 +225,13 @@ The runner refuses an access mode outside a provider's Access modes cell before
- Host prerequisites: none.
- State paths: `~/.config/muse/` (the login in `auth.json`, which the CLI reads and refreshes, `settings.json` and `trust.json`); `~/.local/share/muse/` (the session index, model catalog cache, plugins, skills and runtime state it writes) and `~/Library/Application Support/Muse/` on macOS.
- Child environment: only `PATH` `HOME` `USER` `LOGNAME` `SHELL` `TMPDIR` `LANG` `TERM` `COLORTERM` `TZ` `HTTP_PROXY` `HTTPS_PROXY` `NO_PROXY` `ALL_PROXY` `http_proxy` `https_proxy` `no_proxy` `all_proxy` `SSL_CERT_FILE` `SSL_CERT_DIR` `NODE_EXTRA_CA_CERTS` `META_API_KEY`, and variables starting with `LC_`, `XDG_`.
- Measured with Muse Code 1.4.14 on macOS. Every flag in the argv is in the recorded `muse --help` and `muse exec --help`. A lane runs `exec --json --model <model> --prompt-file <prompt> --workspace <cwd> --worktree off --approval-mode never --approval-judge off` with web tools, reminders, `request_user_input`, foreign personal context and the session log turned off. The effort is `--reasoning-effort <effort>`, omitted for `default`; Muse also accepts `none` and `minimal`, which the runner does not offer. The parent owns the worktree, so Muse creates none. No Muse family is registered, so a lane names a catalog model, such as `muse-spark-1.3` or `muse-wonder-1.0`.
- Measured with Muse Code 1.4.14 on macOS. Every flag in the argv is in the recorded `muse --help` and `muse exec --help`. A lane runs `exec --json --model <model> --prompt-file <prompt> --workspace <cwd> --worktree off --approval-mode never --approval-judge off` with web tools, reminders, `request_user_input`, foreign personal context and the session log turned off. The effort is `--reasoning-effort <effort>`, omitted for `default`; Muse also accepts `none` and `minimal`, which the runner does not offer. The parent owns the worktree, so Muse creates none. The registered family is Muse Wonder Full 1.0; a lane may also name any other Muse catalog model, such as `muse-spark-1.3`, as an unregistered pair.
- A read-only lane adds `--disable-write --disable-shell`. The file-reading tools remain, and a write request fails with `writes are disabled for this session`.
- No Muse writer is confined, so a writer needs the model sheet's opt-in (`isolated-write-full-access`); the runner refuses a bounded `isolated-write` lane before launch. An opted-in writer drops `--disable-write` and `--disable-shell` and keeps Muse's sandbox on. Measured in a linked worktree under the home directory, whose main repository and a sibling directory sat beside it: edits, shell writes and a Python run inside the worktree succeeded. The file tools refused every path outside the workspace (`absolute path is outside the workspace`, `path escapes workspace`) except the system temporary folders. The sandboxed shell failed outside the worktree with `Operation not permitted`, except that it wrote into the main repository's shared `.git`, `/tmp` and `$TMPDIR`. With `--disable-sandbox`, the file tools and the shell wrote into every outside target, so the runner never passes it.
- With `--approval-mode never --approval-judge off`, a refused tool call returns its error to the model and the run continues. Muse reports `Agent delegation: auto unavailable: workspace is untrusted` on stderr, and the lane never passes `--trust-workspace`, so the workspace's skills and rules do not load.
- Muse reads `~/.config/muse/settings.json` in every lane. Its `endpoint_transport` key reroutes every lane to another endpoint: on the measured host, a value that another tool wrote sent each lane to a proxy, and every turn failed with `still unauthorized after a token refresh`. The runner does not override it.
- The environment is the base allowlist plus `META_API_KEY`. The account login is found through `HOME`. `muse login --help` says `META_API_KEY` always takes priority over the account login.
- The preflight runs `muse usage`. It passes when it exits 0 and starts with `Tier: `, with the fixed evidence `authenticated`, because the output names the subscription tier. It also passes when it exits 0 and starts with `No subscription allowance (api_key)`, with the fixed evidence `api-key`, because `META_API_KEY` is the login and the model call checks access. Exit 1 with `muse usage: not logged in:` is `unauthenticated`/77. Any other output is `child-failed`/70.
- The preflight runs `muse usage`. It passes when it exits 0 and starts with `Tier: `, with the fixed evidence `authenticated`, because the output names the subscription tier. It also passes when it exits 0 and starts with `No subscription allowance (api_key)`, with the fixed evidence `api-key`, because `META_API_KEY` is the login and the model call checks access. It also passes when it exits 0 and starts with `No usage data (server_sent_no_usage)`, with the fixed evidence `subscription-no-usage-data`: measured with Muse Code 1.4.14 on Linux, a signed-in account whose window had seen no use printed `No usage data (server_sent_no_usage): the server sent no usage data for this subscription; this can happen before your first use in a new window`, and `muse usage --json` gave `{"allowance":null,"reason":"server_sent_no_usage"}`. The server answered for the subscription, so the login holds and the model call checks access; on that host the model call then returned `API error 429 ... Subscription quota exhausted` as `child-failed`/70, so this output proves the login, not an allowance. Exit 1 with `muse usage: not logged in:` is `unauthenticated`/77. Any other output is `child-failed`/70.
- The `--json` stream is one envelope per line, dispatched on `payload_type`. The reply is the text of the last `run.terminal.*` event, accepted only when its `terminal` is `completed` and the text is not empty. Another terminal is `child-failed`/70 with its reason, except that `model `<id>` does not exist or you lack access` is `unavailable-model`/69. SIGINT exits 130 and SIGTERM 143, each with no terminal event, which is `cancelled`/130; a stream with no terminal event otherwise is `malformed-output`/65. The session is the `session` stream ID, and usage sums the `run.usage` event's per-model tokens. No cost is reported.
- `run.model.configured` repeats the requested model, and no event was shown to name a different served model, so the model proof is the pinned argv (`pinned-argv`).

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
No usage data (server_sent_no_usage): the server sent no usage data for this subscription; this can happen before your first use in a new window

Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ describe("muse preflight", () => {
expect(muse.preflight.classify({ exitCode: 0, stdout: "No subscription allowance (api_key)\n", stderr: "" }, lane()))
.toEqual({ kind: "passed", evidence: "api-key" });
});

it("passes a signed-in `muse usage` whose server sent no usage data, and keeps any other output inconclusive", () => {
expect(muse.preflight.classify({ exitCode: 0, stdout: fixture("usage-no-usage-data.txt"), stderr: "" }, lane()))
.toEqual({ kind: "passed", evidence: "subscription-no-usage-data" });
expect(muse.preflight.classify({ exitCode: 1, stdout: fixture("usage-no-usage-data.txt"), stderr: "" }, lane()))
.toEqual({ kind: "inconclusive" });
expect(muse.preflight.classify({ exitCode: 0, stdout: "No usage data (network_error): offline\n", stderr: "" }, lane()))
.toEqual({ kind: "inconclusive" });
});
});

describe("muse parse", () => {
Expand Down
16 changes: 12 additions & 4 deletions plugins/pstack/skills/poteto-mode/scripts/runner/providers/muse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import { BASE_ALLOWLIST, BASE_PREFIXES, effortArgs, finiteNumber, nullableString
// SIGINT exits 130 and SIGTERM 143, each with no terminal event. Measured with Muse Code 1.4.14.
const SIGNAL_EXITS = [130, 143];

const SIGNED_IN_USAGE: readonly (readonly [prefix: string, evidence: string])[] = [
["Tier: ", "authenticated"],
["No subscription allowance (api_key)", "api-key"],
["No usage data (server_sent_no_usage)", "subscription-no-usage-data"],
];

function events(stdout: string): JsonObject[] | null {
const parsed: JsonObject[] = [];
for (const line of stdout.split("\n")) {
Expand Down Expand Up @@ -74,8 +80,10 @@ export const muse = adapter({
argv: () => ["usage"],
retryAfterUnauthenticatedMs: null,
classify(run) {
if (run.exitCode === 0 && run.stdout.startsWith("Tier: ")) return { kind: "passed", evidence: "authenticated" };
if (run.exitCode === 0 && run.stdout.startsWith("No subscription allowance (api_key)")) return { kind: "passed", evidence: "api-key" };
if (run.exitCode === 0) {
const signedIn = SIGNED_IN_USAGE.find(([prefix]) => run.stdout.startsWith(prefix));
if (signedIn !== undefined) return { kind: "passed", evidence: signedIn[1] };
}
return run.exitCode === 1 && /^muse usage: not logged in:/m.test(run.stderr) ? { kind: "unauthenticated" } : { kind: "inconclusive" };
},
},
Expand Down Expand Up @@ -119,13 +127,13 @@ export const muse = adapter({
"`~/.local/share/muse/` (the session index, model catalog cache, plugins, skills and runtime state it writes) and `~/Library/Application Support/Muse/` on macOS",
],
notes: [
"Measured with Muse Code 1.4.14 on macOS. Every flag in the argv is in the recorded `muse --help` and `muse exec --help`. A lane runs `exec --json --model <model> --prompt-file <prompt> --workspace <cwd> --worktree off --approval-mode never --approval-judge off` with web tools, reminders, `request_user_input`, foreign personal context and the session log turned off. The effort is `--reasoning-effort <effort>`, omitted for `default`; Muse also accepts `none` and `minimal`, which the runner does not offer. The parent owns the worktree, so Muse creates none. No Muse family is registered, so a lane names a catalog model, such as `muse-spark-1.3` or `muse-wonder-1.0`.",
"Measured with Muse Code 1.4.14 on macOS. Every flag in the argv is in the recorded `muse --help` and `muse exec --help`. A lane runs `exec --json --model <model> --prompt-file <prompt> --workspace <cwd> --worktree off --approval-mode never --approval-judge off` with web tools, reminders, `request_user_input`, foreign personal context and the session log turned off. The effort is `--reasoning-effort <effort>`, omitted for `default`; Muse also accepts `none` and `minimal`, which the runner does not offer. The parent owns the worktree, so Muse creates none. The registered family is Muse Wonder Full 1.0; a lane may also name any other Muse catalog model, such as `muse-spark-1.3`, as an unregistered pair.",
"A read-only lane adds `--disable-write --disable-shell`. The file-reading tools remain, and a write request fails with `writes are disabled for this session`.",
"No Muse writer is confined, so a writer needs the model sheet's opt-in (`isolated-write-full-access`); the runner refuses a bounded `isolated-write` lane before launch. An opted-in writer drops `--disable-write` and `--disable-shell` and keeps Muse's sandbox on. Measured in a linked worktree under the home directory, whose main repository and a sibling directory sat beside it: edits, shell writes and a Python run inside the worktree succeeded. The file tools refused every path outside the workspace (`absolute path is outside the workspace`, `path escapes workspace`) except the system temporary folders. The sandboxed shell failed outside the worktree with `Operation not permitted`, except that it wrote into the main repository's shared `.git`, `/tmp` and `$TMPDIR`. With `--disable-sandbox`, the file tools and the shell wrote into every outside target, so the runner never passes it.",
"With `--approval-mode never --approval-judge off`, a refused tool call returns its error to the model and the run continues. Muse reports `Agent delegation: auto unavailable: workspace is untrusted` on stderr, and the lane never passes `--trust-workspace`, so the workspace's skills and rules do not load.",
"Muse reads `~/.config/muse/settings.json` in every lane. Its `endpoint_transport` key reroutes every lane to another endpoint: on the measured host, a value that another tool wrote sent each lane to a proxy, and every turn failed with `still unauthorized after a token refresh`. The runner does not override it.",
"The environment is the base allowlist plus `META_API_KEY`. The account login is found through `HOME`. `muse login --help` says `META_API_KEY` always takes priority over the account login.",
"The preflight runs `muse usage`. It passes when it exits 0 and starts with `Tier: `, with the fixed evidence `authenticated`, because the output names the subscription tier. It also passes when it exits 0 and starts with `No subscription allowance (api_key)`, with the fixed evidence `api-key`, because `META_API_KEY` is the login and the model call checks access. Exit 1 with `muse usage: not logged in:` is `unauthenticated`/77. Any other output is `child-failed`/70.",
"The preflight runs `muse usage`. It passes when it exits 0 and starts with `Tier: `, with the fixed evidence `authenticated`, because the output names the subscription tier. It also passes when it exits 0 and starts with `No subscription allowance (api_key)`, with the fixed evidence `api-key`, because `META_API_KEY` is the login and the model call checks access. It also passes when it exits 0 and starts with `No usage data (server_sent_no_usage)`, with the fixed evidence `subscription-no-usage-data`: measured with Muse Code 1.4.14 on Linux, a signed-in account whose window had seen no use printed `No usage data (server_sent_no_usage): the server sent no usage data for this subscription; this can happen before your first use in a new window`, and `muse usage --json` gave `{\"allowance\":null,\"reason\":\"server_sent_no_usage\"}`. The server answered for the subscription, so the login holds and the model call checks access; on that host the model call then returned `API error 429 ... Subscription quota exhausted` as `child-failed`/70, so this output proves the login, not an allowance. Exit 1 with `muse usage: not logged in:` is `unauthenticated`/77. Any other output is `child-failed`/70.",
"The `--json` stream is one envelope per line, dispatched on `payload_type`. The reply is the text of the last `run.terminal.*` event, accepted only when its `terminal` is `completed` and the text is not empty. Another terminal is `child-failed`/70 with its reason, except that `model `<id>` does not exist or you lack access` is `unavailable-model`/69. SIGINT exits 130 and SIGTERM 143, each with no terminal event, which is `cancelled`/130; a stream with no terminal event otherwise is `malformed-output`/65. The session is the `session` stream ID, and usage sums the `run.usage` event's per-model tokens. No cost is reported.",
"`run.model.configured` repeats the requested model, and no event was shown to name a different served model, so the model proof is the pinned argv (`pinned-argv`).",
],
Expand Down
13 changes: 13 additions & 0 deletions plugins/pstack/skills/poteto-mode/scripts/runner/registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ describe("registry data", () => {
["gemini-3.8-flash", "high"],
["composer-2.5", "default"],
["gemini-3.7-flash", "high"],
["muse-wonder-full-1.0", "max"],
]);
expect(REGISTRY.families.filter((entry) => entry.provider === "claude").map((entry) => [entry.name, entry.model]))
.toEqual([["fable", "fable"], ["opus", "opus"], ["sonnet", "sonnet"], ["opus-5-5", "claude-opus-5-5"], ["haiku-5-5", "claude-haiku-5-5"]]);
Expand Down Expand Up @@ -503,6 +504,18 @@ describe("resolveLane", () => {
.toEqual(expect.arrayContaining(["gpt-6-astra", 'model_reasoning_effort="ultra"']));
});

it("resolves Muse Wonder Full 1.0 at max by default, passes each listed effort as a flag, and rejects ultra", () => {
const muse = (effort = "max") => resolveLane(request({ parent: "claude", provider: "muse", model: "muse-wonder-full-1.0", effort }));
const lane = muse();
expect([lane.family?.name, lane.family?.label, lane.model, lane.cliModel, lane.effort])
.toEqual(["muse-wonder-full-1.0", "Muse Wonder Full 1.0", "muse-wonder-full-1.0", "muse-wonder-full-1.0", "max"]);
expect(effortsOf(REGISTRY.families.find((entry) => entry.name === "muse-wonder-full-1.0")!)).toEqual(["low", "medium", "high", "xhigh", "max"]);
expect(muse("high").adapter.launch.argv(muse("high"), { sharedGitDir: null, providerSidecar: null }))
.toEqual(expect.arrayContaining(["--model", "muse-wonder-full-1.0", "--reasoning-effort", "high"]));
expect(() => muse("ultra")).toThrow("effort ultra is not offered for muse:muse-wonder-full-1.0; choose one of: low, medium, high, xhigh, max");
expect(resolveLane(request({ parent: "claude", provider: "muse", model: "muse-wonder-1.0", effort: "high" })).family).toBeNull();
});

it("maps each Devin effort to its CLI model ID and keeps the descriptor's model for the receipt", () => {
const devin = (model: string, effort: string, mode = "read-only") =>
resolveLane(request({ parent: "claude", provider: "devin", model, effort, mode }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,15 @@ export const FAMILIES = [
defaultEffort: "high",
upstream: null,
}),
family({
name: "muse-wonder-full-1.0",
label: "Muse Wonder Full 1.0",
provider: "muse",
model: "muse-wonder-full-1.0",
efforts: UP_TO_MAX,
defaultEffort: "max",
upstream: null,
}),
] as const;
export type FamilyName = (typeof FAMILIES)[number]["name"];

Expand Down Expand Up @@ -219,4 +228,5 @@ export const RELEASED_PAIRS = [
{ pair: "cursor:gemini-3.7-flash", family: "gemini-3.7-flash" },
{ pair: "claude:claude-haiku-5-5", family: "haiku-5-5" },
{ pair: "codex:gpt-6-astra", family: "astra" },
{ pair: "muse:muse-wonder-full-1.0", family: "muse-wonder-full-1.0" },
] as const satisfies readonly ReleasedPair<FamilyName>[];