Skip to content

hack: omni + genie-nats context isolation for multi-user agents#65

Open
rafaelcalassara wants to merge 1 commit intoautomagik-dev:devfrom
rafaelcalassara:hack/omni-agent-context-isolation
Open

hack: omni + genie-nats context isolation for multi-user agents#65
rafaelcalassara wants to merge 1 commit intoautomagik-dev:devfrom
rafaelcalassara:hack/omni-agent-context-isolation

Conversation

@rafaelcalassara
Copy link
Copy Markdown

New Community Hack

Title: Omni + Genie-NATS — Context Isolation for Multi-User Agents
Category: Hooks & integration (Hack 9)

Problem: A genie-nats agent connected to a Telegram/WhatsApp/Discord instance via omni connect handles 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 — context poisoning. Prompt discipline alone is insufficient.

Solution:

  • Classify omni commands into explicit-scope (safe: send --to, where --json, turns get, chats get, etc.) and global-state (unsafe: say, open, history, all verb commands).
  • Whitelist only explicit-scope commands in the agent's .claude/settings.local.json.
  • Derive chat_id from NATS payload env vars (OMNI_CHAT_ID, etc.) or omni where --json — never enumerate via chats list / persons search.
  • Document the contract in AGENTS.md so the LLM self-limits.

Key gotcha highlighted: Claude Code evaluates permissions in deny → ask → allow order — deny always wins regardless of specificity. A broad deny: ["Bash(omni *)"] will silently kill a narrow allow rule. Use defaultMode + explicit allow list instead.

Benefit: Zero cross-user context poisoning with many concurrent chats on the same agent. Defense in depth — the harness blocks unsafe commands even if the LLM tries them.

When to use: Any genie-nats agent on an omni channel with multiple concurrent users (Telegram bots, WhatsApp, Discord), or any autonomous LLM exposed to a CLI with global/session state.

Includes:

  • Full classification table of safe vs unsafe omni commands
  • say vs send comparison
  • Complete settings.local.json template with allow/deny rules
  • Code snippets for chat_id discovery via env vars and where --json
  • <Warning> about deny precedence
  • <Info> recommending documentation of the contract in AGENTS.md

Submitted via /genie-hacks contribute

Copilot AI review requested due to automatic review settings April 23, 2026 21:53
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 23, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 419705d2-cf0d-4fa6-a3d5-e40355e782a0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds a new section to the documentation detailing context isolation for multi-user agents using Omni and Genie-NATS. The feedback suggests strengthening the validation logic for environment variables, consolidating redundant permission patterns, and including necessary shell commands like echo, grep, and [ in the allowed permissions list to ensure the provided examples work as intended.

Comment thread genie/hacks.mdx
CTX=$(omni where --json)
CHAT_ID=$(echo "$CTX" | jq -r '.chat.id')
INSTANCE_ID=$(echo "$CTX" | jq -r '.instance.id')
[ -n "$CHAT_ID" ] && [ "$CHAT_ID" != "null" ] || { echo "no active turn" >&2; exit 1; }
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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; }

Comment thread genie/hacks.mdx
Comment on lines +383 to +384
"Bash(omni where --json)",
"Bash(omni where --json*)",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The permission "Bash(omni where --json)" is redundant as it is covered by the glob pattern "Bash(omni where --json*)". Consolidating these improves the clarity of the security configuration.

      "Bash(omni where --json*)",

Comment thread genie/hacks.mdx
Comment on lines +393 to +394
"Bash(jq *)",
"Bash(env)"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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([ *)"

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e6138ac646

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread genie/hacks.mdx
"Bash(omni where --json*)",
"Bash(omni turns get *)",
"Bash(omni turns list --chat *)",
"Bash(omni turns list --agent *)",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new “Hack 9” entry to the Genie hacks documentation describing how to prevent cross-user context leakage when a multi-user genie-nats agent uses the Omni CLI.

Changes:

  • Document a safe/unsafe classification of Omni commands for multi-user agents.
  • Provide example patterns for deriving chat_id (env vars / where --json) and a .claude/settings.local.json permissions template.
  • Add warnings about Claude Code permissions evaluation order and recommended operational guidance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread genie/hacks.mdx
| `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 |
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lists omni events get <id> as a safe command, but the Omni CLI docs in this repo define omni events subcommands like list/search/timeline/metrics/... and do not document an events get. Replace this with a documented command (e.g., a suitably filtered omni events list ...) or remove it so readers don’t copy a non-existent command.

Suggested change
| `omni messages get <id>` / `omni events get <id>` | Explicit resource ID |
| `omni messages get <id>` | Explicit resource ID |

Copilot uses AI. Check for mistakes.
Comment thread genie/hacks.mdx
| `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 done --text "..."` | Closes only the current turn |
Copy link

Copilot AI Apr 23, 2026

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.

Suggested change
| `omni done --text "..."` | Closes only the current turn |
| `omni turns close <turn-id>` | Explicit turn ID; avoids relying on current global state |

Copilot uses AI. Check for mistakes.
Comment thread genie/hacks.mdx
"Bash(omni chats messages *)",
"Bash(omni messages get *)",
"Bash(omni events get *)",
"Bash(omni done*)",
Copy link

Copilot AI Apr 23, 2026

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.

Suggested change
"Bash(omni done*)",

Copilot uses AI. Check for mistakes.
Comment thread genie/hacks.mdx
</Warning>

<Info>
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.
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: “fricton” → “friction”.

Suggested change
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.

Copilot uses AI. Check for mistakes.
Comment thread genie/hacks.mdx

```bash
# Option A — NATS payload env vars (preferred)
env | grep -i omni # inspect your connector once
Copy link

Copilot AI Apr 23, 2026

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.

Suggested change
env | grep -i omni # inspect your connector once
env # inspect output for OMNI_* vars once

Copilot uses AI. Check for mistakes.
Comment thread genie/hacks.mdx
Comment on lines +343 to +345
- 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`
Copy link

Copilot AI Apr 23, 2026

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.

Suggested change
- 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 uses AI. Check for mistakes.
Comment thread genie/hacks.mdx
Comment on lines +327 to +335
**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 |
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

omni where --json is listed as safe, but there’s no omni where command documented under omni/cli/*.mdx in this repo. Either link/add the missing Omni CLI docs for where (including its JSON shape) or adjust this hack to rely only on documented commands/env vars.

Suggested change
**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 |
**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 by resolving the current turn via `omni turns get <turn-id>` using the turn ID from env — 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 turns get <turn-id>` | Explicit turn ID; use with the current turn ID from env to recover chat context safely |

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants