From baf14edd79de4905c3685dcac1833da075b07e46 Mon Sep 17 00:00:00 2001 From: dimavrem22 Date: Thu, 25 Jun 2026 04:01:38 +0000 Subject: [PATCH 1/9] feat: tag codex harness on signup + plugin-setup prompt Pass harness="codex" on Inkbox.signup so self-signups are attributed to this harness, and add a channel-prompt note telling the agent to ask the human for permission before configuring the plugin when it self-signed up without it already set up. Co-Authored-By: Claude Opus 4.8 (1M context) --- inkbox_codex/prompts.py | 4 ++++ inkbox_codex/setup_wizard.py | 1 + 2 files changed, 5 insertions(+) diff --git a/inkbox_codex/prompts.py b/inkbox_codex/prompts.py index c751c48..ca89897 100644 --- a/inkbox_codex/prompts.py +++ b/inkbox_codex/prompts.py @@ -46,6 +46,10 @@ their reply comes back as the answer. - Long tasks are fine: the human walked away from the keyboard on purpose. Text them the result when you're done, not play-by-play. +- If you signed yourself up to Inkbox without this plugin already set + up, ask the human for permission before you configure it — the plugin + wires native messaging channels straight into your runtime, so that's + the human's call to make. # Outbound messaging diff --git a/inkbox_codex/setup_wizard.py b/inkbox_codex/setup_wizard.py index 740f6a5..ef1dd71 100644 --- a/inkbox_codex/setup_wizard.py +++ b/inkbox_codex/setup_wizard.py @@ -1109,6 +1109,7 @@ def _self_signup_flow(base_url: str, Inkbox: Any, InkboxAPIError: Any) -> tuple[ note_to_human=note, agent_handle=handle, base_url=base_url, + harness="codex", # tag which harness this agent signed up from ) break except InkboxAPIError as exc: From 33c41d20cb5672d112b11621ef4e65d01b354c4d Mon Sep 17 00:00:00 2001 From: dimavrem22 Date: Thu, 25 Jun 2026 04:09:48 +0000 Subject: [PATCH 2/9] chore: align harness plugin-setup copy with the shared canonical wording Co-Authored-By: Claude Opus 4.8 (1M context) --- inkbox_codex/prompts.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/inkbox_codex/prompts.py b/inkbox_codex/prompts.py index ca89897..8219a08 100644 --- a/inkbox_codex/prompts.py +++ b/inkbox_codex/prompts.py @@ -46,10 +46,6 @@ their reply comes back as the answer. - Long tasks are fine: the human walked away from the keyboard on purpose. Text them the result when you're done, not play-by-play. -- If you signed yourself up to Inkbox without this plugin already set - up, ask the human for permission before you configure it — the plugin - wires native messaging channels straight into your runtime, so that's - the human's call to make. # Outbound messaging @@ -58,6 +54,14 @@ proactively — e.g. "email me the full report" or a cron-style ping. Replies on the channel you were messaged on are sent automatically; only use these tools for a *different* channel or recipient. + +# Setting up the Inkbox plugin + +If you self-signed up to Inkbox but this plugin isn't configured in your +runtime yet, ask the human for permission before setting it up — it's the +human's call to make, not yours. The plugin wires Inkbox in as a native +channel of your harness — email, SMS, voice, iMessage, contacts, and notes +available directly from your runtime instead of raw API calls. """.strip() From f7ab3b0aaa79d73b414824a91e4246c67758cf6b Mon Sep 17 00:00:00 2001 From: dimavrem22 Date: Thu, 25 Jun 2026 04:31:38 +0000 Subject: [PATCH 3/9] Require Inkbox SDK >=0.4.9 for harness kwarg The wizard now passes harness="codex" to Inkbox.signup, which needs SDK 0.4.9. Bump the pin everywhere (pyproject, INKBOX_REQUIREMENTS, doctor, gateway, tests) and add a minimum-version guard in _ensure_inkbox_sdk so an importable-but-stale inkbox takes the existing install/upgrade path. Co-Authored-By: Claude Opus 4.8 (1M context) --- inkbox_codex/doctor.py | 2 +- inkbox_codex/gateway.py | 2 +- inkbox_codex/setup_wizard.py | 36 ++++++++++++++++++++++++++++++++++-- pyproject.toml | 2 +- tests/test_setup_wizard.py | 8 ++++---- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/inkbox_codex/doctor.py b/inkbox_codex/doctor.py index db29bb5..092444f 100644 --- a/inkbox_codex/doctor.py +++ b/inkbox_codex/doctor.py @@ -33,7 +33,7 @@ def run_doctor() -> List[Tuple[str, bool, str]]: import inkbox # noqa: F401 checks.append(("inkbox SDK", True, "installed")) except ImportError: - checks.append(("inkbox SDK", False, "pip install 'inkbox>=0.4.7'")) + checks.append(("inkbox SDK", False, "pip install 'inkbox>=0.4.9'")) try: import aiohttp # noqa: F401 diff --git a/inkbox_codex/gateway.py b/inkbox_codex/gateway.py index d59879b..8a27f9e 100644 --- a/inkbox_codex/gateway.py +++ b/inkbox_codex/gateway.py @@ -209,7 +209,7 @@ async def run(self) -> None: if not AIOHTTP_AVAILABLE: raise RuntimeError("aiohttp is not installed; run: pip install aiohttp") if not INKBOX_AVAILABLE: - raise RuntimeError("inkbox SDK is not installed; run: pip install 'inkbox>=0.4.7'") + raise RuntimeError("inkbox SDK is not installed; run: pip install 'inkbox>=0.4.9'") if not self.cfg.api_key or not self.cfg.identity: raise RuntimeError("INKBOX_API_KEY and INKBOX_IDENTITY must be set (see README)") diff --git a/inkbox_codex/setup_wizard.py b/inkbox_codex/setup_wizard.py index ef1dd71..54f5cda 100644 --- a/inkbox_codex/setup_wizard.py +++ b/inkbox_codex/setup_wizard.py @@ -36,7 +36,9 @@ # Packages the wizard itself needs to talk to Inkbox during setup. The # gateway's Codex CLI dependency is checked by doctor. -INKBOX_REQUIREMENTS = ("inkbox>=0.4.7", "aiohttp>=3.9") +INKBOX_REQUIREMENTS = ("inkbox>=0.4.9", "aiohttp>=3.9") +# The wizard passes harness="codex" to Inkbox.signup, which needs SDK >= 0.4.9. +MIN_INKBOX_VERSION = (0, 4, 9) _BRACKETED_PASTE_PATTERN = re.compile(r"\x1b\[\s*200~|\x1b\[\s*201~") # Bundled avatar attached to the agent's Inkbox contact card during setup. @@ -366,6 +368,30 @@ def _load_inkbox_symbols() -> dict[str, Any]: } +def _inkbox_version_too_old() -> bool: + """Return True when the installed Inkbox SDK predates MIN_INKBOX_VERSION. + + Returns: + bool: True if an outdated ``inkbox`` is installed, else False. + """ + try: + import importlib.metadata as importlib_metadata + + raw = importlib_metadata.version("inkbox") + except Exception: + # Can't determine the version; let the import path decide. + return False + try: + # Prefer packaging when present for PEP 440-correct comparison. + from packaging.version import Version + + return Version(raw) < Version(".".join(str(p) for p in MIN_INKBOX_VERSION)) + except Exception: + # Fall back to a simple numeric-tuple comparison of the leading parts. + parts = tuple(int(p) for p in re.findall(r"\d+", raw)[: len(MIN_INKBOX_VERSION)]) + return parts < MIN_INKBOX_VERSION + + def _ensure_inkbox_sdk() -> dict[str, Any] | None: """Import the Inkbox SDK, offering to install it into this env if missing. @@ -373,7 +399,13 @@ def _ensure_inkbox_sdk() -> dict[str, Any] | None: dict[str, Any] | None: SDK symbols on success, None if unavailable. """ try: - return _load_inkbox_symbols() + symbols = _load_inkbox_symbols() + # An importable-but-stale SDK lacks harness="codex"; upgrade like a miss. + if not _inkbox_version_too_old(): + return symbols + first_error = ( + f"inkbox SDK is older than {'.'.join(str(p) for p in MIN_INKBOX_VERSION)}" + ) except Exception as exc: first_error = exc diff --git a/pyproject.toml b/pyproject.toml index 6c1c762..fd659e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ description = "Inkbox bridge for Codex — talk to your coding agent over email, requires-python = ">=3.10" dependencies = [ "aiohttp>=3.9", - "inkbox>=0.4.7", + "inkbox>=0.4.9", "segno>=1.5", # terminal QR codes for the iMessage connect step ] diff --git a/tests/test_setup_wizard.py b/tests/test_setup_wizard.py index 923688e..df813b0 100644 --- a/tests/test_setup_wizard.py +++ b/tests/test_setup_wizard.py @@ -83,7 +83,7 @@ def test_install_command_prefers_uv_when_available(monkeypatch): "install", "--python", "/tmp/venv/bin/python", - "inkbox>=0.4.7", + "inkbox>=0.4.9", "aiohttp>=3.9", ]] @@ -93,10 +93,10 @@ def test_install_command_falls_back_to_pip_and_ensurepip(monkeypatch): monkeypatch.setattr(setup_wizard.shutil, "which", lambda _name: None) assert setup_wizard._install_commands() == [ - [["/tmp/venv/bin/python", "-m", "pip", "install", "inkbox>=0.4.7", "aiohttp>=3.9"]], + [["/tmp/venv/bin/python", "-m", "pip", "install", "inkbox>=0.4.9", "aiohttp>=3.9"]], [ ["/tmp/venv/bin/python", "-m", "ensurepip", "--upgrade"], - ["/tmp/venv/bin/python", "-m", "pip", "install", "inkbox>=0.4.7", "aiohttp>=3.9"], + ["/tmp/venv/bin/python", "-m", "pip", "install", "inkbox>=0.4.9", "aiohttp>=3.9"], ], ] @@ -115,7 +115,7 @@ def fail_import(): out = capsys.readouterr().out assert "/tmp/venv/bin/python" in out assert "uv pip install --python" in out - assert "inkbox>=0.4.7" in out + assert "inkbox>=0.4.9" in out # ---------------------------------------------------------------------- From c65fd5bdea511e408f6f82856be8183783681cf9 Mon Sep 17 00:00:00 2001 From: dimavrem22 Date: Thu, 25 Jun 2026 04:44:58 +0000 Subject: [PATCH 4/9] Bump inkbox SDK pin to 0.4.10 for agent-signup harness 0.4.10 is the release that introduces the agent-signup harness param; 0.4.9 was an earlier release that predates it. Co-Authored-By: Claude Opus 4.8 (1M context) --- inkbox_codex/doctor.py | 2 +- inkbox_codex/gateway.py | 2 +- inkbox_codex/setup_wizard.py | 6 +++--- pyproject.toml | 2 +- tests/test_setup_wizard.py | 8 ++++---- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/inkbox_codex/doctor.py b/inkbox_codex/doctor.py index 092444f..b67f958 100644 --- a/inkbox_codex/doctor.py +++ b/inkbox_codex/doctor.py @@ -33,7 +33,7 @@ def run_doctor() -> List[Tuple[str, bool, str]]: import inkbox # noqa: F401 checks.append(("inkbox SDK", True, "installed")) except ImportError: - checks.append(("inkbox SDK", False, "pip install 'inkbox>=0.4.9'")) + checks.append(("inkbox SDK", False, "pip install 'inkbox>=0.4.10'")) try: import aiohttp # noqa: F401 diff --git a/inkbox_codex/gateway.py b/inkbox_codex/gateway.py index 8a27f9e..0f04450 100644 --- a/inkbox_codex/gateway.py +++ b/inkbox_codex/gateway.py @@ -209,7 +209,7 @@ async def run(self) -> None: if not AIOHTTP_AVAILABLE: raise RuntimeError("aiohttp is not installed; run: pip install aiohttp") if not INKBOX_AVAILABLE: - raise RuntimeError("inkbox SDK is not installed; run: pip install 'inkbox>=0.4.9'") + raise RuntimeError("inkbox SDK is not installed; run: pip install 'inkbox>=0.4.10'") if not self.cfg.api_key or not self.cfg.identity: raise RuntimeError("INKBOX_API_KEY and INKBOX_IDENTITY must be set (see README)") diff --git a/inkbox_codex/setup_wizard.py b/inkbox_codex/setup_wizard.py index 54f5cda..597259e 100644 --- a/inkbox_codex/setup_wizard.py +++ b/inkbox_codex/setup_wizard.py @@ -36,9 +36,9 @@ # Packages the wizard itself needs to talk to Inkbox during setup. The # gateway's Codex CLI dependency is checked by doctor. -INKBOX_REQUIREMENTS = ("inkbox>=0.4.9", "aiohttp>=3.9") -# The wizard passes harness="codex" to Inkbox.signup, which needs SDK >= 0.4.9. -MIN_INKBOX_VERSION = (0, 4, 9) +INKBOX_REQUIREMENTS = ("inkbox>=0.4.10", "aiohttp>=3.9") +# The wizard passes harness="codex" to Inkbox.signup, which needs SDK >= 0.4.10. +MIN_INKBOX_VERSION = (0, 4, 10) _BRACKETED_PASTE_PATTERN = re.compile(r"\x1b\[\s*200~|\x1b\[\s*201~") # Bundled avatar attached to the agent's Inkbox contact card during setup. diff --git a/pyproject.toml b/pyproject.toml index fd659e2..2b851e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ description = "Inkbox bridge for Codex — talk to your coding agent over email, requires-python = ">=3.10" dependencies = [ "aiohttp>=3.9", - "inkbox>=0.4.9", + "inkbox>=0.4.10", "segno>=1.5", # terminal QR codes for the iMessage connect step ] diff --git a/tests/test_setup_wizard.py b/tests/test_setup_wizard.py index df813b0..4175cab 100644 --- a/tests/test_setup_wizard.py +++ b/tests/test_setup_wizard.py @@ -83,7 +83,7 @@ def test_install_command_prefers_uv_when_available(monkeypatch): "install", "--python", "/tmp/venv/bin/python", - "inkbox>=0.4.9", + "inkbox>=0.4.10", "aiohttp>=3.9", ]] @@ -93,10 +93,10 @@ def test_install_command_falls_back_to_pip_and_ensurepip(monkeypatch): monkeypatch.setattr(setup_wizard.shutil, "which", lambda _name: None) assert setup_wizard._install_commands() == [ - [["/tmp/venv/bin/python", "-m", "pip", "install", "inkbox>=0.4.9", "aiohttp>=3.9"]], + [["/tmp/venv/bin/python", "-m", "pip", "install", "inkbox>=0.4.10", "aiohttp>=3.9"]], [ ["/tmp/venv/bin/python", "-m", "ensurepip", "--upgrade"], - ["/tmp/venv/bin/python", "-m", "pip", "install", "inkbox>=0.4.9", "aiohttp>=3.9"], + ["/tmp/venv/bin/python", "-m", "pip", "install", "inkbox>=0.4.10", "aiohttp>=3.9"], ], ] @@ -115,7 +115,7 @@ def fail_import(): out = capsys.readouterr().out assert "/tmp/venv/bin/python" in out assert "uv pip install --python" in out - assert "inkbox>=0.4.9" in out + assert "inkbox>=0.4.10" in out # ---------------------------------------------------------------------- From 11b8206a8f6001867b70a9d6122e8c4a577b2090 Mon Sep 17 00:00:00 2001 From: dimavrem22 Date: Thu, 25 Jun 2026 05:10:30 +0000 Subject: [PATCH 5/9] Require human confirmation before plugin setup Rework the setup-guidance copy so the agent confirms with its human and sets up the plugin together, never starting on its own. Co-Authored-By: Claude Opus 4.8 (1M context) --- inkbox_codex/prompts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inkbox_codex/prompts.py b/inkbox_codex/prompts.py index 8219a08..8a02106 100644 --- a/inkbox_codex/prompts.py +++ b/inkbox_codex/prompts.py @@ -58,8 +58,8 @@ # Setting up the Inkbox plugin If you self-signed up to Inkbox but this plugin isn't configured in your -runtime yet, ask the human for permission before setting it up — it's the -human's call to make, not yours. The plugin wires Inkbox in as a native +runtime yet, don't set it up on your own — confirm with your human and do +it together before you start. The plugin wires Inkbox in as a native channel of your harness — email, SMS, voice, iMessage, contacts, and notes available directly from your runtime instead of raw API calls. """.strip() From 21405e1e04eb43ad6b3e79162ae34b50e64a2891 Mon Sep 17 00:00:00 2001 From: dimavrem22 Date: Thu, 25 Jun 2026 05:33:25 +0000 Subject: [PATCH 6/9] Clarify Inkbox plugin self-setup requires asking human permission first Co-Authored-By: Claude Opus 4.8 (1M context) --- inkbox_codex/prompts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inkbox_codex/prompts.py b/inkbox_codex/prompts.py index 8a02106..b6127c1 100644 --- a/inkbox_codex/prompts.py +++ b/inkbox_codex/prompts.py @@ -58,8 +58,8 @@ # Setting up the Inkbox plugin If you self-signed up to Inkbox but this plugin isn't configured in your -runtime yet, don't set it up on your own — confirm with your human and do -it together before you start. The plugin wires Inkbox in as a native +runtime yet, ask your human for permission before you start — once they +approve, you can set it up yourself. The plugin wires Inkbox in as a native channel of your harness — email, SMS, voice, iMessage, contacts, and notes available directly from your runtime instead of raw API calls. """.strip() From cfe117467e55ccfdc1c60f03c706fef5d96da2b3 Mon Sep 17 00:00:00 2001 From: dimavrem22 Date: Thu, 25 Jun 2026 18:21:11 +0000 Subject: [PATCH 7/9] chore: drop redundant plugin-setup prompt block The plugin's setup wizard already configures the plugin during signup, so a separate agent-facing "ask permission, then set it up yourself" instruction is redundant. Drop it; keep the harness= signup tagging. Co-Authored-By: Claude Opus 4.8 (1M context) --- inkbox_codex/prompts.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/inkbox_codex/prompts.py b/inkbox_codex/prompts.py index b6127c1..c751c48 100644 --- a/inkbox_codex/prompts.py +++ b/inkbox_codex/prompts.py @@ -54,14 +54,6 @@ proactively — e.g. "email me the full report" or a cron-style ping. Replies on the channel you were messaged on are sent automatically; only use these tools for a *different* channel or recipient. - -# Setting up the Inkbox plugin - -If you self-signed up to Inkbox but this plugin isn't configured in your -runtime yet, ask your human for permission before you start — once they -approve, you can set it up yourself. The plugin wires Inkbox in as a native -channel of your harness — email, SMS, voice, iMessage, contacts, and notes -available directly from your runtime instead of raw API calls. """.strip() From aeedf78cb4dc102f3d5364b9fc7c4296a9590eba Mon Sep 17 00:00:00 2001 From: dimavrem22 Date: Thu, 25 Jun 2026 18:24:00 +0000 Subject: [PATCH 8/9] ci: run pytest on PRs Mirror openclaw-plugin's CI. The inkbox SDK is deliberately not installed (tests mock it, and inkbox>=0.4.10 with the harness= kwarg isn't on PyPI yet), so CI installs only the deps the tests actually import. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/ci.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..066c41d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + # The inkbox SDK is intentionally not installed here: the tests mock it, + # and the pinned inkbox>=0.4.10 (with the harness= signup kwarg) isn't on + # PyPI yet. Install only the deps the tests actually import. + - name: Install test deps + run: pip install pytest aiohttp segno + + - name: Test + run: pytest -q From 75dbbf3a634e96f00bb6cc21c0bb87a519a3cdf5 Mon Sep 17 00:00:00 2001 From: dimavrem22 Date: Fri, 26 Jun 2026 20:12:10 +0000 Subject: [PATCH 9/9] chore: trim out-of-place harness/version comments Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/ci.yml | 4 +--- inkbox_codex/setup_wizard.py | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 066c41d..517bf22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,9 +17,7 @@ jobs: with: python-version: "3.12" - # The inkbox SDK is intentionally not installed here: the tests mock it, - # and the pinned inkbox>=0.4.10 (with the harness= signup kwarg) isn't on - # PyPI yet. Install only the deps the tests actually import. + # inkbox is mocked in the tests, so install only what they import. - name: Install test deps run: pip install pytest aiohttp segno diff --git a/inkbox_codex/setup_wizard.py b/inkbox_codex/setup_wizard.py index 597259e..ea07298 100644 --- a/inkbox_codex/setup_wizard.py +++ b/inkbox_codex/setup_wizard.py @@ -37,7 +37,6 @@ # Packages the wizard itself needs to talk to Inkbox during setup. The # gateway's Codex CLI dependency is checked by doctor. INKBOX_REQUIREMENTS = ("inkbox>=0.4.10", "aiohttp>=3.9") -# The wizard passes harness="codex" to Inkbox.signup, which needs SDK >= 0.4.10. MIN_INKBOX_VERSION = (0, 4, 10) _BRACKETED_PASTE_PATTERN = re.compile(r"\x1b\[\s*200~|\x1b\[\s*201~") @@ -379,7 +378,6 @@ def _inkbox_version_too_old() -> bool: raw = importlib_metadata.version("inkbox") except Exception: - # Can't determine the version; let the import path decide. return False try: # Prefer packaging when present for PEP 440-correct comparison. @@ -400,7 +398,6 @@ def _ensure_inkbox_sdk() -> dict[str, Any] | None: """ try: symbols = _load_inkbox_symbols() - # An importable-but-stale SDK lacks harness="codex"; upgrade like a miss. if not _inkbox_version_too_old(): return symbols first_error = ( @@ -1141,7 +1138,7 @@ def _self_signup_flow(base_url: str, Inkbox: Any, InkboxAPIError: Any) -> tuple[ note_to_human=note, agent_handle=handle, base_url=base_url, - harness="codex", # tag which harness this agent signed up from + harness="codex", ) break except InkboxAPIError as exc: