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
2 changes: 1 addition & 1 deletion .github/workflows/live-channels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
ln -sfn "$GITHUB_WORKSPACE" "$HERMES_HOME/plugins/inkbox"
hermes plugins enable inkbox
"$HERMES_HOME/bin/uv" pip install --python "$HERMES_HOME/hermes-agent/venv/bin/python3" \
'inkbox>=0.5.0,<1.0.0' 'aiohttp>=3.9' 'segno>=1.5'
'inkbox>=0.5.1,<1.0.0' 'aiohttp>=3.9' 'segno>=1.5'

- name: Configure AUT identity + model (${{ matrix.mode }})
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/live-external-events.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jobs:
ln -sfn "$GITHUB_WORKSPACE" "$HERMES_HOME/plugins/inkbox"
hermes plugins enable inkbox
"$HERMES_HOME/bin/uv" pip install --python "$HERMES_HOME/hermes-agent/venv/bin/python3" \
'inkbox>=0.5.0,<1.0.0' 'aiohttp>=3.9' 'segno>=1.5'
'inkbox>=0.5.1,<1.0.0' 'aiohttp>=3.9' 'segno>=1.5'

- name: Configure AUT identity + model
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/live-voice.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ jobs:
ln -sfn "$GITHUB_WORKSPACE" "$HERMES_HOME/plugins/inkbox"
hermes plugins enable inkbox
"$HERMES_HOME/bin/uv" pip install --python "$HERMES_HOME/hermes-agent/venv/bin/python3" \
'inkbox>=0.5.0,<1.0.0' 'aiohttp>=3.9' 'segno>=1.5' fastapi uvicorn
'inkbox>=0.5.1,<1.0.0' 'aiohttp>=3.9' 'segno>=1.5' fastapi uvicorn

- name: Configure AUT identity + model + speech path (${{ matrix.scenario }})
env:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
run: |
uv venv --python ${{ matrix.python-version }}
uv pip install \
"inkbox @ git+https://github.com/inkbox-ai/inkbox.git@8f4b37c56cd153a2acc6cfabe27dbbeb43510f00#subdirectory=sdk/python" \
"inkbox @ git+https://github.com/inkbox-ai/inkbox.git@199bbd27c8dab2f70e379de52ca9cc910b0e141d#subdirectory=sdk/python" \
'aiohttp>=3.9' 'segno>=1.5' 'pytest>=8' 'ruff>=0.11.0'

- name: Lint
Expand Down Expand Up @@ -67,7 +67,7 @@ jobs:
run: |
uv venv --python 3.12
uv pip install \
"inkbox @ git+https://github.com/inkbox-ai/inkbox.git@8f4b37c56cd153a2acc6cfabe27dbbeb43510f00#subdirectory=sdk/python" \
"inkbox @ git+https://github.com/inkbox-ai/inkbox.git@199bbd27c8dab2f70e379de52ca9cc910b0e141d#subdirectory=sdk/python" \
'aiohttp>=3.9' 'segno>=1.5' 'pytest>=8' 'ruff>=0.11.0'
uv pip install "hermes-agent @ git+https://github.com/NousResearch/hermes-agent.git@main"

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ hermes gateway restart

`hermes inkbox setup` walks the active Hermes install through Inkbox configuration:

1. Installs or upgrades `inkbox>=0.5.0,<1.0.0` and `aiohttp>=3.9` in the Hermes Python environment when needed.
1. Installs or upgrades `inkbox>=0.5.1,<1.0.0` and `aiohttp>=3.9` in the Hermes Python environment when needed.
2. Authenticates to Inkbox, or starts self-signup if you do not have an API key yet.
3. Resolves or creates the Inkbox agent identity for this Hermes gateway.
4. Optionally provisions a local US phone number so SMS and voice are available.
Expand All @@ -96,13 +96,13 @@ The setup wizard installs dependencies into the Python environment that runs Her
If the wizard prints a missing-SDK warning, use the exact command it prints. It will look like this:

```bash
/path/to/hermes/venv/bin/python3 -m pip install 'inkbox>=0.5.0,<1.0.0' 'aiohttp>=3.9'
/path/to/hermes/venv/bin/python3 -m pip install 'inkbox>=0.5.1,<1.0.0' 'aiohttp>=3.9'
```

When `uv` is available, the wizard prefers:

```bash
uv pip install --python /path/to/hermes/venv/bin/python3 'inkbox>=0.5.0,<1.0.0' 'aiohttp>=3.9'
uv pip install --python /path/to/hermes/venv/bin/python3 'inkbox>=0.5.1,<1.0.0' 'aiohttp>=3.9'
```

Do not use plain `pip install inkbox aiohttp` unless the wizard tells you to; plain `pip` may point at pyenv, Homebrew, system Python, or another virtualenv.
Expand Down Expand Up @@ -328,7 +328,7 @@ The plugin registers all `skills/*/SKILL.md` files with Hermes.
| `inkbox-imessage-responder` | Sending, replying to, or triaging iMessage |
| `inkbox-outbound-calling` | Placing calls to numbers or contacts |
| `inkbox-call-review` | Current-call/post-call context; historical call reads are not exposed in Hermes |
| `inkbox-contact-lookup` | Resolving, creating, or updating contacts visible to the configured identity |
| `inkbox-contact-lookup` | Resolving, creating, or updating organization-wide contacts |
| `inkbox-contact-rules` | Explaining server-side contact rules; rule edit tools are not exposed in Hermes |
| `inkbox-identity-access` | Explaining identity access; grant/revoke tools are not exposed in Hermes |
| `inkbox-notes-memory` | Explaining note limitations; Inkbox note tools are not exposed in Hermes |
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description = "Inkbox platform plugin for Hermes Agent"
requires-python = ">=3.11"
dependencies = [
"aiohttp>=3.9",
"inkbox>=0.5.0,<1.0.0",
"inkbox>=0.5.1,<1.0.0",
"segno>=1.5",
]

Expand Down
2 changes: 1 addition & 1 deletion setup_wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def print_warning(message: str) -> None:
masked_secret_prompt = None


INKBOX_MIN_VERSION = "0.5.0"
INKBOX_MIN_VERSION = "0.5.1"
INKBOX_REQUIREMENTS = (f"inkbox>={INKBOX_MIN_VERSION},<1.0.0", "aiohttp>=3.9", "segno>=1.5")
_BRACKETED_PASTE_PATTERN = re.compile(r"\x1b\[\s*200~|\x1b\[\s*201~")
_AVATAR_PATH = Path(__file__).resolve().parent / "assets" / "hermes_with_iphone.png"
Expand Down
10 changes: 5 additions & 5 deletions skills/inkbox-contact-lookup/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
name: inkbox-contact-lookup
description: Use when the user asks "who is X", "what's the email for Y", "find a contact named Z", "save this contact", or any question that needs contact context. Hermes can read and write Inkbox contacts visible to this identity, but does not expose contact admin tools.
description: Use when the user asks "who is X", "what's the email for Y", "find a contact named Z", "save this contact", or any question that needs contact context. Contacts are shared across the Inkbox organization.
user-invocable: false
---

# Inkbox contact lookup

Hermes is the Inkbox social-assistant tier. It receives contact context on inbound email, SMS, iMessage, and calls when Inkbox resolves the sender, and it can read or update contacts visible to the configured identity.
Hermes receives contact context on inbound email, SMS, iMessage, and calls when Inkbox resolves the sender, and it can read or update the organization's shared contacts.

## Hermes tool availability

Expand All @@ -32,9 +32,9 @@ Hermes is the Inkbox social-assistant tier. It receives contact context on inbou

## Access semantics

- Contact context is **filtered server-side** by per-identity grants. If Inkbox does not include a resolved contact marker, this identity may not have access or the sender may be unknown.
- Hermes contact tools operate only on contacts visible/writable to the configured identity.
- Grant management is handled by the `inkbox-identity-access` skill when the user asks to share contacts across Inkbox identities.
- Every identity in the organization can read contacts. Creating, updating, or deleting a contact affects the shared address book.
- If Inkbox does not include a resolved contact marker, the sender may be unknown or ambiguous.
- Contacts do not have per-identity access grants.

## What this skill does NOT cover

Expand Down
24 changes: 10 additions & 14 deletions skills/inkbox-identity-access/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
---
name: inkbox-identity-access
description: Use when the user asks which Inkbox agent identities can see a contact or note, or asks to grant/revoke cross-identity access to contacts or notes. Hermes does not expose identity-access tools; explain the limitation.
description: Use when the user asks which Inkbox agent identities can see a contact or note, or asks to grant/revoke cross-identity note access. Contacts are organization-wide; Hermes does not expose note-access tools.
user-invocable: false
---

# Inkbox identity access

Use this skill when discussing per-identity visibility for Inkbox contacts and notes.
Use this skill when explaining organization-wide contact visibility or per-identity note access.

## Hermes tool availability

- Hermes does not register `inkbox_list_contact_access`, `inkbox_grant_contact_access`, `inkbox_revoke_contact_access`, `inkbox_list_note_access`, `inkbox_grant_note_access`, or `inkbox_revoke_note_access`.
- This plugin cannot grant or revoke cross-identity access directly.
- Direct the user to Inkbox Console or an admin-capable host/plugin tier when they need access changes.
- Hermes does not register `inkbox_list_note_access`, `inkbox_grant_note_access`, or `inkbox_revoke_note_access`.
- Contacts do not have per-identity access controls.
- Direct the user to Inkbox Console or a host with note-access tools when they need note access changes.

## Workflow

1. Clarify whether the request is about contact visibility or note visibility.
2. If the user needs an actual access change, state that Hermes cannot perform it directly and summarize the requested change for Console/admin execution.
3. For contacts, explain the concepts:
- Grant a specific identity with `identityId`.
- Use `wildcard: true` only when the user wants every active identity to see the contact.
- Revoke by `identityId`.
4. For notes, explain the concepts:
- Grant and revoke only by explicit `identityId`; notes do not support wildcard grants.
5. If the user gives an agent handle instead of an identity UUID, explain that Console/admin tooling may need the identity id.
2. For contacts, explain that every identity in the organization can see them and access cannot be granted or revoked per identity.
3. For notes, explain that grants use an explicit `identityId` and that Hermes cannot change them directly.
4. Summarize the requested note access change for execution in Inkbox Console or a host with note-access tools.
5. If the user gives an agent handle instead of an identity UUID, explain that note access tooling may need the identity id.

## Safety

Access changes affect what other Inkbox agent identities can see. Confirm the target identity and object before granting broad or wildcard contact access.
Note access changes affect what other Inkbox agent identities can see. Confirm the target identity and note before requesting a change.
8 changes: 4 additions & 4 deletions tests/test_contact_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,10 @@ def test_lookup_contact_requires_one_filter(monkeypatch):
assert "exactly one" in too_many["error"]


def test_contact_schemas_preserve_identity_scoped_semantics():
assert "visible to this configured identity" in tools.LOOKUP_CONTACT_SCHEMA["description"]
assert "visible to this configured identity" in tools.LIST_CONTACTS_SCHEMA["description"]
assert "contact access rules" in tools.CREATE_CONTACT_SCHEMA["description"]
def test_contact_schemas_describe_organization_wide_semantics():
assert "organization-wide" in tools.LOOKUP_CONTACT_SCHEMA["description"]
assert "organization-wide" in tools.LIST_CONTACTS_SCHEMA["description"]
assert "organization-wide" in tools.CREATE_CONTACT_SCHEMA["description"]


def test_contact_write_tools_validate_required_inputs(monkeypatch):
Expand Down
8 changes: 4 additions & 4 deletions tests/test_setup_wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def test_install_command_prefers_uv_when_available(monkeypatch):
"install",
"--python",
"/tmp/hermes/venv/bin/python",
"inkbox>=0.5.0,<1.0.0",
"inkbox>=0.5.1,<1.0.0",
"aiohttp>=3.9",
"segno>=1.5",
]]
Expand All @@ -37,10 +37,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/hermes/venv/bin/python", "-m", "pip", "install", "inkbox>=0.5.0,<1.0.0", "aiohttp>=3.9", "segno>=1.5"]],
[["/tmp/hermes/venv/bin/python", "-m", "pip", "install", "inkbox>=0.5.1,<1.0.0", "aiohttp>=3.9", "segno>=1.5"]],
[
["/tmp/hermes/venv/bin/python", "-m", "ensurepip", "--upgrade"],
["/tmp/hermes/venv/bin/python", "-m", "pip", "install", "inkbox>=0.5.0,<1.0.0", "aiohttp>=3.9", "segno>=1.5"],
["/tmp/hermes/venv/bin/python", "-m", "pip", "install", "inkbox>=0.5.1,<1.0.0", "aiohttp>=3.9", "segno>=1.5"],
],
]

Expand All @@ -59,7 +59,7 @@ def fail_import():
out = capsys.readouterr().out
assert "/tmp/hermes/venv/bin/python" in out
assert "uv pip install --python" in out
assert "inkbox>=0.5.0,<1.0.0" in out
assert "inkbox>=0.5.1,<1.0.0" in out
assert "aiohttp>=3.9" in out


Expand Down
8 changes: 4 additions & 4 deletions tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,7 @@ def inkbox_place_call(args: dict, **kwargs) -> str:

def _place():
if not hasattr(identity, "place_call"):
raise RuntimeError("Inkbox SDK identity has no place_call method (upgrade inkbox to >=0.5.0)")
raise RuntimeError("Inkbox SDK identity has no place_call method (upgrade inkbox to >=0.5.1)")
try:
return identity.place_call(
to_number=to_number,
Expand Down Expand Up @@ -965,7 +965,7 @@ def _place():

LOOKUP_CONTACT_SCHEMA = {
"name": "inkbox_lookup_contact",
"description": "Reverse-lookup Inkbox contacts by exactly one email/phone filter. Returns contacts visible to this configured identity.",
"description": "Reverse-lookup organization-wide Inkbox contacts by exactly one email/phone filter.",
"parameters": {
"type": "object",
"properties": {
Expand All @@ -980,7 +980,7 @@ def _place():

LIST_CONTACTS_SCHEMA = {
"name": "inkbox_list_contacts",
"description": "Search/list Inkbox contacts visible to this configured identity. Use for name-based queries like 'who is Alex?'.",
"description": "Search/list organization-wide Inkbox contacts. Use for name-based queries like 'who is Alex?'.",
"parameters": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -1047,7 +1047,7 @@ def _place():

CREATE_CONTACT_SCHEMA = {
"name": "inkbox_create_contact",
"description": "Create an Inkbox address-book contact visible according to Inkbox contact access rules.",
"description": "Create an organization-wide Inkbox address-book contact.",
"parameters": {
"type": "object",
"properties": dict(_CONTACT_WRITE_PROPERTIES),
Expand Down
Loading