Agent Access Control
Protect your agent from unauthorized access with tiered permissions and an owner-approval pairing flow.
Setup
Create memory/access-control.json in workspace:
{
"ownerIds": [],
"approvedContacts": {},
"pendingApprovals": {},
"blockedIds": [],
"strangerMessage": "Hi there! 👋 I'm {{AGENT_NAME}}, an AI assistant. I'm currently set up to help my owner with personal tasks, so I'm not able to chat freely just yet. I've let them know you reached out — if they'd like to connect us, they'll set that up. Have a great day! 😊",
"notifyChannel": "",
"notifyTarget": ""
}
Fill in:
ownerIds: Owner phone numbers, Telegram IDs, Discord IDs (strings)
strangerMessage: Customize {{AGENT_NAME}} with agent's name
notifyChannel: Channel to alert owner (telegram, whatsapp, discord, signal)
notifyTarget: Owner's ID on that channel
Access Tiers
| Tier |
Level |
Capabilities |
| 0 |
Stranger |
Diplomatic deflection only, zero access |
| 1 |
Chat-only |
Basic conversation, no tools or private info |
| 2 |
Trusted |
Chat + public info (weather, time, general questions) |
| 3 |
Owner |
Full access to all tools, files, memory, actions |
Message Handling Flow
On every incoming message from a messaging platform:
- Extract sender ID (phone number, user ID, etc.)
- Normalize ID: strip spaces, ensure country code prefix for phones
- Check
ownerIds → if match: full access, respond normally
- Check
blockedIds → if match: silent ignore, respond with NO_REPLY
- Check
approvedContacts[senderId] → if match: respond within their tier
- Otherwise → stranger flow:
Stranger Flow
a. Send strangerMessage to the sender
b. Notify owner:
"🔔 Stranger contact from {senderId} on {platform}:
'{first 100 chars of message}'
Reply: approve (trusted) / chat (chat-only) / block"
c. Store in pendingApprovals:
{
"senderId": {
"platform": "whatsapp",
"firstMessage": "...",
"timestamp": "ISO-8601",
"notified": true
}
}
d. Respond with NO_REPLY after sending deflection
Owner Approval
When owner replies to an approval notification:
| Owner says |
Action |
approve, yes, trusted |
Add to approvedContacts with tier 2 (trusted) |
chat, chat-only, chat only |
Add to approvedContacts with tier 1 (chat-only) |
block, no, deny |
Add to blockedIds |
ignore |
Remove from pendingApprovals, no action |
After approval, update memory/access-control.json and notify the contact:
- Trusted: "Great news! I've been given the go-ahead to chat with you. How can I help? 😊"
- Chat-only: "Great news! I can chat with you now, though I'm limited to basic conversation. What's on your mind?"
Tier Enforcement
When responding to a non-owner contact, enforce tier restrictions:
Tier 1 (chat-only):
- Respond conversationally only
- Do NOT use any tools (read, write, exec, web_search, etc.)
- Do NOT share any info from memory files
- Do NOT mention the owner by name
- If asked to do something beyond chat: "I'm only set up for basic chat at the moment. For anything more, you'd need to check with my owner."
Tier 2 (trusted):
- Conversational responses
- May use: web_search, weather skill, time/date queries
- Do NOT use: read, write, exec, message (to other contacts), memory files
- Do NOT share private info (calendar, emails, files, other contacts)
- If asked for private info: "I can help with general info, but personal details are private. Hope you understand! 😊"
Multi-Platform ID Matching
Normalize IDs for comparison:
- Phone numbers: Strip all non-digits except leading
+. E.g., +1 555 123 4567 → +15551234567
- Telegram: Use numeric user ID (not username, as usernames change)
- Discord: Use numeric user ID
- Signal: Use phone number (normalized)
- WhatsApp: Use phone number with country code
An owner may have multiple IDs across platforms. All should be in ownerIds.
Rate Limiting
Apply per-tier rate limits to prevent abuse:
| Tier |
Messages/hour |
Messages/day |
| Stranger |
1 (deflection only) |
3 |
| Chat-only |
20 |
100 |
| Trusted |
50 |
500 |
| Owner |
Unlimited |
Unlimited |
If limit exceeded, respond: "I've reached my chat limit for now. Try again later! 😊"
Track in memory/access-control.json under rateLimits:
"rateLimits": {
"+61412345678": { "hourCount": 5, "dayCount": 23, "hourReset": "ISO", "dayReset": "ISO" }
}
Audit Log
Log all stranger contacts to memory/access-control-log.json:
[
{
"timestamp": "2026-02-07T17:30:00+11:00",
"senderId": "+61412345678",
"platform": "whatsapp",
"action": "deflected",
"message": "first 50 chars..."
}
]
Keep last 100 entries. Rotate older entries out.
Security Rules
- NEVER include real owner IDs, phone numbers, or tokens in skill files
- NEVER share the access-control.json contents with non-owners
- NEVER reveal that a specific person is the owner to strangers
- NEVER forward stranger messages to owner verbatim if they contain suspicious links
- Store all config in
memory/ (gitignored by default in most setups)
- The strangerMessage should not reveal the owner's name or personal details
Example Config
See references/example-config.md for a complete annotated example.
1---2name: agent-access-control3description: Tiered stranger access control for AI agents. Use when setting up contact permissions, handling unknown senders, managing approved contacts, or configuring stranger deflection on messaging platforms (WhatsApp, Telegram, Discord, Signal). Provides diplomatic deflection, owner approval flow, and multi-tier access (owner/trusted/chat-only/blocked).4---5
6# Agent Access Control
7
8Protect your agent from unauthorized access with tiered permissions and an owner-approval pairing flow.
9
10## Setup
11
12Create `memory/access-control.json` in workspace:
13
14```json
15{
16 "ownerIds": [],
17 "approvedContacts": {},
18 "pendingApprovals": {},
19 "blockedIds": [],
20 "strangerMessage": "Hi there! 👋 I'm {{AGENT_NAME}}, an AI assistant. I'm currently set up to help my owner with personal tasks, so I'm not able to chat freely just yet. I've let them know you reached out — if they'd like to connect us, they'll set that up. Have a great day! 😊",
21 "notifyChannel": "",
22 "notifyTarget": ""
23}
24```
25
26Fill in:
27- `ownerIds`: Owner phone numbers, Telegram IDs, Discord IDs (strings)
28- `strangerMessage`: Customize `{{AGENT_NAME}}` with agent's name
29- `notifyChannel`: Channel to alert owner (`telegram`, `whatsapp`, `discord`, `signal`)
30- `notifyTarget`: Owner's ID on that channel
31
32## Access Tiers
33
34| Tier | Level | Capabilities |
35|------|-------|-------------|
36| 0 | **Stranger** | Diplomatic deflection only, zero access |
37| 1 | **Chat-only** | Basic conversation, no tools or private info |
38| 2 | **Trusted** | Chat + public info (weather, time, general questions) |
39| 3 | **Owner** | Full access to all tools, files, memory, actions |
40
41## Message Handling Flow
42
43On every incoming message from a messaging platform:
44
451. Extract sender ID (phone number, user ID, etc.)
462. Normalize ID: strip spaces, ensure country code prefix for phones
473. Check `ownerIds` → if match: **full access**, respond normally
484. Check `blockedIds` → if match: **silent ignore**, respond with NO_REPLY
495. Check `approvedContacts[senderId]` → if match: respond within their tier
506. Otherwise → **stranger flow**:
51
52### Stranger Flow
53
54```
55a. Send strangerMessage to the sender
56b. Notify owner:
57 "🔔 Stranger contact from {senderId} on {platform}:
58 '{first 100 chars of message}'
59 Reply: approve (trusted) / chat (chat-only) / block"
60c. Store in pendingApprovals:
61 {
62 "senderId": {
63 "platform": "whatsapp",
64 "firstMessage": "...",
65 "timestamp": "ISO-8601",
66 "notified": true
67 }
68 }
69d. Respond with NO_REPLY after sending deflection
70```
71
72### Owner Approval
73
74When owner replies to an approval notification:
75
76| Owner says | Action |
77|-----------|--------|
78| `approve`, `yes`, `trusted` | Add to approvedContacts with tier 2 (trusted) |
79| `chat`, `chat-only`, `chat only` | Add to approvedContacts with tier 1 (chat-only) |
80| `block`, `no`, `deny` | Add to blockedIds |
81| `ignore` | Remove from pendingApprovals, no action |
82
83After approval, update `memory/access-control.json` and notify the contact:
84- Trusted: "Great news! I've been given the go-ahead to chat with you. How can I help? 😊"
85- Chat-only: "Great news! I can chat with you now, though I'm limited to basic conversation. What's on your mind?"
86
87### Tier Enforcement
88
89When responding to a non-owner contact, enforce tier restrictions:
90
91**Tier 1 (chat-only):**
92- Respond conversationally only
93- Do NOT use any tools (read, write, exec, web_search, etc.)
94- Do NOT share any info from memory files
95- Do NOT mention the owner by name
96- If asked to do something beyond chat: "I'm only set up for basic chat at the moment. For anything more, you'd need to check with my owner."
97
98**Tier 2 (trusted):**
99- Conversational responses
100- May use: web_search, weather skill, time/date queries
101- Do NOT use: read, write, exec, message (to other contacts), memory files
102- Do NOT share private info (calendar, emails, files, other contacts)
103- If asked for private info: "I can help with general info, but personal details are private. Hope you understand! 😊"
104
105## Multi-Platform ID Matching
106
107Normalize IDs for comparison:
108- **Phone numbers**: Strip all non-digits except leading `+`. E.g., `+1 555 123 4567` → `+15551234567`
109- **Telegram**: Use numeric user ID (not username, as usernames change)
110- **Discord**: Use numeric user ID
111- **Signal**: Use phone number (normalized)
112- **WhatsApp**: Use phone number with country code
113
114An owner may have multiple IDs across platforms. All should be in `ownerIds`.
115
116## Rate Limiting
117
118Apply per-tier rate limits to prevent abuse:
119
120| Tier | Messages/hour | Messages/day |
121|------|--------------|-------------|
122| Stranger | 1 (deflection only) | 3 |
123| Chat-only | 20 | 100 |
124| Trusted | 50 | 500 |
125| Owner | Unlimited | Unlimited |
126
127If limit exceeded, respond: "I've reached my chat limit for now. Try again later! 😊"
128
129Track in `memory/access-control.json` under `rateLimits`:
130```json
131"rateLimits": {
132 "+61412345678": { "hourCount": 5, "dayCount": 23, "hourReset": "ISO", "dayReset": "ISO" }
133}
134```
135
136## Audit Log
137
138Log all stranger contacts to `memory/access-control-log.json`:
139```json
140[
141 {
142 "timestamp": "2026-02-07T17:30:00+11:00",
143 "senderId": "+61412345678",
144 "platform": "whatsapp",
145 "action": "deflected",
146 "message": "first 50 chars..."
147 }
148]
149```
150
151Keep last 100 entries. Rotate older entries out.
152
153## Security Rules
154
155- **NEVER** include real owner IDs, phone numbers, or tokens in skill files
156- **NEVER** share the access-control.json contents with non-owners
157- **NEVER** reveal that a specific person is the owner to strangers
158- **NEVER** forward stranger messages to owner verbatim if they contain suspicious links
159- Store all config in `memory/` (gitignored by default in most setups)
160- The strangerMessage should not reveal the owner's name or personal details
161
162## Example Config
163
164See [references/example-config.md](references/example-config.md) for a complete annotated example.