Skip to content

marimo pair prompt exits 0 when the skill is missing — #9029's SystemExit never landed #10705

Description

@jungleBadger

Describe the bug

marimo pair prompt --claude prints "could not be found" when the skill is missing, then
emits the pair prompt anyway and exits 0. So the documented usage

claude "$(uvx marimo@latest pair prompt --url http://localhost:2718 --claude)"

launches an agent session whose first instruction is "Use the /marimo-pair skill" for a
skill that is not installed. The warning goes to stderr, where command substitution leaves
it easy to miss, and the agent starts with no way to do what it was asked.

This looks like a source change that went missing rather than a design decision. #9029
("fix: exit with non-zero code when marimo-pair skill is missing") describes two changes:

The prompt command printed an error when the skill was not found but continued executing
and exited successfully. Now it raises SystemExit(1) so callers can detect the failure.
Also fixes the test assertions to match the actual error message ("could not be found").

The second half landed and was clearly correct — the tests were asserting a stale
"not installed" string that the source no longer produced. But the merged commit
2bb4d538c touches only tests/_cli/test_cli_pair.py:

-                assert result.exit_code != 0, flag
-                assert "not installed" in result.output, flag
+                assert result.exit_code == 0, flag
+                assert "could not be found" in result.output, flag
-        assert result.exit_code != 0
-        assert "not installed" in result.output
+        assert result.exit_code == 0
+        assert "could not be found" in result.output

Both tests were red before that commit, failing on the exit code as well as the message:

$ git checkout 2bb4d538c~1
$ pytest tests/_cli/test_cli_pair.py -q
>       assert result.exit_code != 0
E       assert 0 != 0
FAILED tests/_cli/test_cli_pair.py::TestPairPrompt::test_prompt_skill_missing
FAILED tests/_cli/test_cli_pair.py::TestPairPromptWithToken::test_with_token_and_skill_missing_fails
2 failed, 14 passed

So the exit-code assertions were green-lit against the unchanged source instead of the
source being changed to satisfy them. The SystemExit(1) never reached
marimo/_cli/pair/commands.py, and has never existed anywhere in the package:

$ git log --all -S 'SystemExit' -- marimo/_cli/pair/
$ grep -rnE 'SystemExit|sys\.exit|raise click|Abort' marimo/_cli/pair/
(both empty)

The net effect is that the tests now assert the behaviour #9029 set out to remove, which
makes it read as intentional. test_with_token_and_skill_missing_fails is named for a
failure it asserts does not happen — worth renaming alongside any fix.

Interaction with #10704

Please consider sequencing this after #10704. Today the validator result is cosmetic, so a
false negative only costs a spurious warning. Once a missing skill exits non-zero, any false
negative becomes a hard failure.

_claude_skill_dirs() currently produces one for a project-scoped install: it resolves
.claude from Path.cwd() alone, so a skill at <repo>/.claude/skills/marimo-pair/ is
invisible from any subdirectory. (A global ~/.claude/skills install is unaffected — that
path is checked directly.) #10704 fixes the project-scoped case. Landing this one first
would turn that warning into a hard blocker for anyone with a project-scoped install whose
notebooks live below the repository root.

Will you submit a PR?

  • Yes — happy to, once there's agreement on the intended behaviour.

Two questions worth settling first, since both affect callers:

  1. Should a missing skill be fatal for all agent flags, or only when the prompt is being
    piped into an agent? A user reading the output themselves may reasonably want the prompt.
  2. Should --with-token still write the token file before exiting?

Environment

Reproducible from source; not version-specific. Confirmed on main at 1269547a7, and the
behaviour is present in the released 0.24.0.

marimo:  0.24.0 (released) / main @ 1269547a7
OS:      Darwin 25.6.0 (arm64)
Python:  3.13 / 3.14

Code to reproduce

Exit code is 0 and the prompt is emitted even with the skill absent:

from unittest.mock import patch
from click.testing import CliRunner
from marimo._cli.cli import main
from marimo._cli.pair.commands import AgentConfig

with patch.object(AgentConfig, "has_skill", return_value=False):
    result = CliRunner().invoke(
        main, ["pair", "prompt", "--url", "http://localhost:2718", "--claude"]
    )

print("exit_code =", result.exit_code)                                  # 0
print("warned    =", "could not be found" in result.output)              # True
print("prompt emitted =", "Use the /marimo-pair skill" in result.output) # True

Or from a shell, with no skill installed:

$ cd "$(mktemp -d)"
$ marimo pair prompt --url http://localhost:2718 --claude >/tmp/prompt.txt
The marimo-pair skill for Claude Code could not be found.
...
$ echo $?
0
$ head -1 /tmp/prompt.txt
Use the /marimo-pair skill to pair-program on a running marimo notebook.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions