-
Notifications
You must be signed in to change notification settings - Fork 1
hack: omni + genie-nats context isolation for multi-user agents #65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -320,6 +320,101 @@ See the [Hooks reference](/genie/config/hooks) for the full list of NATS subject | |||||||||||||
|
|
||||||||||||||
| --- | ||||||||||||||
|
|
||||||||||||||
| ### Hack 9: Omni + Genie-NATS — Context Isolation for Multi-User Agents | ||||||||||||||
|
|
||||||||||||||
| **Problem:** A genie-nats agent connected to a Telegram/WhatsApp/Discord instance via `omni connect` gets spoken to by multiple users in parallel. The omni CLI exposes global-state verbs (`omni say`, `omni open`, `omni use`, `omni react`, `omni history`, ...) that operate on an "active chat". If the agent calls any of them, replies leak to the wrong user — classic context poisoning. Prompt discipline alone won't hold; you need a harness-enforced permission boundary. | ||||||||||||||
|
|
||||||||||||||
| **Solution:** Classify omni commands into **explicit-scope** (safe) and **global-state** (unsafe). Whitelist only explicit-scope commands in the agent's `.claude/settings.local.json`. Teach the agent to derive `chat_id` from the NATS turn payload (env vars) or `omni where --json` — never from enumeration like `omni chats list`. | ||||||||||||||
|
|
||||||||||||||
| **Safe commands** (scope always explicit): | ||||||||||||||
|
|
||||||||||||||
| | Command | Why safe | | ||||||||||||||
| |---|---| | ||||||||||||||
| | `omni send --to <chat-id> ...` | Destination mandatory, ignores global state — use instead of `say` | | ||||||||||||||
| | `omni where --json` | Read-only; process-scoped by turn dispatcher | | ||||||||||||||
| | `omni turns get <turn-id>` | Explicit turn ID | | ||||||||||||||
| | `omni turns list --chat <id>` / `--agent <id>` | Filter binds scope | | ||||||||||||||
| | `omni chats get <id>` / `omni chats messages <id>` | Explicit chat ID | | ||||||||||||||
| | `omni messages get <id>` / `omni events get <id>` | Explicit resource ID | | ||||||||||||||
|
||||||||||||||
| | `omni messages get <id>` / `omni events get <id>` | Explicit resource ID | | |
| | `omni messages get <id>` | Explicit resource ID | |
Copilot
AI
Apr 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
omni done --text "..." is presented as a safe command, but omni done isn’t documented under omni/cli/*.mdx (and appears to not exist). Consider replacing this with a documented command (e.g., omni turns close <turn-id> with an explicit ID) or removing it to avoid misleading copy/paste.
| | `omni done --text "..."` | Closes only the current turn | | |
| | `omni turns close <turn-id>` | Explicit turn ID; avoids relying on current global state | |
Copilot
AI
Apr 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This “Unsafe commands” list includes several Omni commands that aren’t documented under omni/cli/*.mdx in this repo (e.g., open/close/use/history, persons list, chats delete). If these are real commands, it’d help to link to their docs; otherwise consider pruning/renaming them to match the documented CLI so the classification table stays accurate.
| - Global-state verbs: `open`, `close`, `use`, `say`, `react`, `listen`, `imagine`, `film`, `speak`, `see`, `history` | |
| - Unfiltered enumeration: `chats list`, `events list/search/timeline`, `turns list` (no filter), `persons list/search` | |
| - Destructive/admin: `turns close-all`, `chats delete/archive/hide/mute`, `instances`, `channels`, `agents`, `providers`, `routes`, `keys`, `access`, `webhooks`, `settings`, `automations`, `start/stop/restart/install/doctor/resync/replay`, `batch`, `dead-letters`, `payloads`, `logs`, `auth`, `config` | |
| - Global-state commands: `omni say <text>` and any command that relies on the active chat, agent, provider, or other CLI context instead of an explicit ID or flag | |
| - Unfiltered enumeration: `omni chats list`, `omni events list/search/timeline`, `omni turns list` without `--chat <id>` or `--agent <id>` | |
| - Destructive or admin actions: `omni turns close-all`, chat-wide state changes such as archive/hide/mute, and workspace-wide admin or lifecycle commands that can affect resources beyond the current turn |
Copilot
AI
Apr 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The snippet uses env | grep -i omni, but the permissions template only allows Bash(env) and doesn’t allow grep/pipelines. If this is intended to be run by the agent, it will trigger extra permission prompts; either change the snippet to env (manual inspection) or add an explicit allow rule covering the pipeline you expect to run.
| env | grep -i omni # inspect your connector once | |
| env # inspect output for OMNI_* vars once |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The validation logic only checks for CHAT_ID. Since the subsequent omni send command uses both --to "$CHAT_ID" and --instance "$INSTANCE_ID", it is safer to ensure both variables are present and not "null" to avoid execution errors or targeting the wrong instance in a multi-user setup.
[ -n "$CHAT_ID" ] && [ "$CHAT_ID" != "null" ] && [ -n "$INSTANCE_ID" ] && [ "$INSTANCE_ID" != "null" ] || { echo "no active turn" >&2; exit 1; }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove agent-scoped turns listing from safe allowlist
omni turns list --agent * is marked safe and explicitly allowed here, but the Omni CLI docs define omni turns as an admin turn management surface and --agent filters by agent ID, not by current chat (omni/cli/system.mdx, omni turns + omni turns list options). In a multi-user bot, one agent ID typically serves many chats, so this command can enumerate other users’ turns and reintroduce cross-user context leakage, contradicting the isolation guarantee in this hack.
Useful? React with 👍 / 👎.
Copilot
AI
Apr 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The permissions template allows Bash(omni done*), but omni done isn’t documented under omni/cli/*.mdx. If you drop/rename the command in the hack, update this allow rule accordingly so the template stays copy/pasteable.
| "Bash(omni done*)", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The allow list is missing permissions for echo, grep, and [, which are used in the recommended snippets (Option A and B). Additionally, Bash(env) should be updated to Bash(env*) to support the piped command env | grep. Adding these ensures the agent can execute the discovery logic autonomously without manual approval prompts.
"Bash(jq *)",
"Bash(env*)",
"Bash(echo *)",
"Bash(grep *)",
"Bash([ *)"
Copilot
AI
Apr 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: “fricton” → “friction”.
| Also document the contract in `AGENTS.md` so the LLM self-limits and you see fewer approval prompts during autonomous loops. List the allowed commands and explicitly forbid the verb commands — this reduces fricton even before the harness layer kicks in. | |
| Also document the contract in `AGENTS.md` so the LLM self-limits and you see fewer approval prompts during autonomous loops. List the allowed commands and explicitly forbid the verb commands — this reduces friction even before the harness layer kicks in. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
omni where --jsonis listed as safe, but there’s noomni wherecommand documented underomni/cli/*.mdxin this repo. Either link/add the missing Omni CLI docs forwhere(including its JSON shape) or adjust this hack to rely only on documented commands/env vars.