feat: RSO observation system, child safety, Discord adapter, Telegram watchdog, email attachments
Core agent improvements: - RSO (Relevance Scoring & Observation) system: interaction_logger, memory_scorer, signal_detector - Memory access logging (memory_access_log table) for relevance scoring; high-signal turn detection - Rich conversation storage for notable turns; compact_conversation truncates long user messages - Task-type classifier (query/action/analysis/creative) for observation tagging - Nested sub-agent visibility: deep delegations now register against the main agent's manager Child safety (Gabriel profile): - child_safety.py: filtering, audit logging, prompt constants for restricted sessions - .kiro/specs/child-safety-profile: requirements, design, tasks specs - GABRIEL_BOT_PROPOSAL.md: initial proposal doc - Reduced context window (10 msgs) and tutor-mode identity for restricted users Telegram adapter: - Polling watchdog: auto-restarts updater if polling drops unexpectedly - get_me() with exponential-backoff retry on NetworkError at startup - Correct stop() ordering: signal watchdog before cancelling tasks Email / Gmail: - send_email: supports file attachments (attachments list param) - get_email: surfaces attachment metadata in response Scheduled tasks / weather: - Remove OpenWeatherMap API calls from morning-weather task; use wttr.in exclusively - New scheduled tasks and scheduler state persistence Discord: - adapters/discord/__init__.py scaffold - discord-plugin: MCP plugin for Claude Code Discord integration (server.ts, skills, config) Infrastructure: - n8n workflow exports (garvis_webhook, content_pipeline variants) - memory_workspace: context, homelab-repo-updates, weekly observation summaries, error logs - UCS C240 migration plan doc - requirements.txt: new deps - .claude/settings.json, fix_hooks.py: hook/permission tuning
This commit is contained in:
338
.kiro/specs/child-safety-profile/requirements.md
Normal file
338
.kiro/specs/child-safety-profile/requirements.md
Normal file
@@ -0,0 +1,338 @@
|
||||
# Requirements — Child Safety Profile
|
||||
|
||||
## Overview
|
||||
|
||||
Add a restricted child user profile to Ajarbot that allows a 13-year-old to use the bot as an
|
||||
educational and creative tool — focused on gaming, Lua scripting, and Roblox Studio — while
|
||||
preventing access to age-inappropriate content. Parents retain full oversight via an audit log.
|
||||
|
||||
---
|
||||
|
||||
## User Stories
|
||||
|
||||
### REQ-01 — Child User Access
|
||||
**As a parent**, I want to add my gabriel as an allowed user on Slack so he can interact with
|
||||
the bot using his own account.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- His Slack user ID is mapped to a named username (e.g., `gabriel`) in `adapters.local.yaml`
|
||||
- His username appears in the `allowed_users` list
|
||||
- He can send messages and receive responses through the existing Slack adapter
|
||||
- His session is isolated from the parent's session (separate conversation history)
|
||||
|
||||
---
|
||||
|
||||
### REQ-02 — Age-Appropriate System Persona
|
||||
**As a parent**, I want the bot to behave differently for my gabriel — patient, educational, and
|
||||
enthusiastic about game dev — rather than presenting the full Garvis homelab persona.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- Child users receive a modified system prompt that replaces homelab/admin context with
|
||||
an educational game-dev tutor persona
|
||||
- Tone is encouraging, uses simple language, avoids jargon where possible
|
||||
- References to SSH, Proxmox, home network, or admin tooling are suppressed for child users
|
||||
- Son's profile (`memory_workspace/users/gabriel.md`) captures his interests, age, and learning style
|
||||
|
||||
---
|
||||
|
||||
### REQ-03 — Context-Aware Content Filtering (Input)
|
||||
**As a parent**, I want the bot to block genuinely harmful requests without false-positiving
|
||||
on legitimate game development questions that use words like "shoot", "kill", "weapon", or "knife"
|
||||
in a coding/game context.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- A preprocessor runs on every inbound message from a child user before it reaches the LLM
|
||||
- The preprocessor uses **intent patterns**, not keyword matching — a block requires both a
|
||||
harm verb and a real-world target/context
|
||||
- Game development context signals (e.g., `in my game`, `roblox`, `lua`, `script`, `code`,
|
||||
`function`, `NPC`, `hitbox`) exempt a message from weapon/violence keyword blocks
|
||||
- The following are always blocked regardless of context:
|
||||
- Real-world harm instructions ("how do I hurt/stab/shoot a person")
|
||||
- Requests for actual weapon construction
|
||||
- Sexual or explicit content
|
||||
- Social engineering or personal data requests
|
||||
- Content with no plausible game/educational framing
|
||||
- Blocked messages receive a friendly, non-alarming response explaining the bot can't help
|
||||
with that topic
|
||||
- The following are always allowed regardless of words used:
|
||||
- Lua scripting and Roblox Studio mechanics
|
||||
- Horror game design (atmosphere, enemy AI, damage systems, jump scares)
|
||||
- Game weapon mechanics, hitboxes, damage values, animations
|
||||
- General coding help (Python, JavaScript basics)
|
||||
- School subjects, creative writing, general knowledge
|
||||
|
||||
---
|
||||
|
||||
### REQ-04 — Context-Aware Content Filtering (Output)
|
||||
**As a parent**, I want a secondary check on what the bot sends back so that even if the LLM
|
||||
produces something borderline, it is caught before delivery.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- A postprocessor scans every outgoing response to a child user
|
||||
- Detects and replaces responses that contain explicit language, adult content, or real-world
|
||||
harm instructions that slipped through the system prompt
|
||||
- If a response is flagged, a safe fallback message is sent and the event is logged
|
||||
- Clean responses pass through unmodified with zero added latency beyond the scan
|
||||
|
||||
---
|
||||
|
||||
### REQ-05 — System Prompt Guardrails
|
||||
**As a parent**, I want the LLM itself to understand the rules so it handles gray-area
|
||||
questions correctly without requiring every edge case to be coded explicitly.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- Child users receive a guardrail block appended to their system prompt on every turn
|
||||
- The guardrail block explicitly tells the LLM:
|
||||
- Game dev / horror game design / weapon mechanics in a game context = encouraged
|
||||
- Real-world harm, adult content, explicit language = refuse politely
|
||||
- If unsure, treat the question as game/educational context if any signal supports it
|
||||
- The guardrail block is injected in `_build_system_prompt()` when the username is in the
|
||||
configured `RESTRICTED_USERS` list
|
||||
|
||||
---
|
||||
|
||||
### REQ-06 — Tool Restrictions
|
||||
**As a parent**, I want my gabriel to be unable to trigger homelab tools, SSH commands, file
|
||||
system operations, or admin-level actions even if he asks.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- System prompt for child users instructs the LLM never to use SSH, file system, Proxmox,
|
||||
network, or infrastructure tools
|
||||
- This is enforced at the system prompt level (model instruction), not by removing MCP servers
|
||||
- Tool invocations from child users that attempt admin tooling are logged as anomalies
|
||||
|
||||
---
|
||||
|
||||
### REQ-07 — Parental Audit Log
|
||||
**As a parent**, I want a complete, searchable record of every conversation my gabriel has with
|
||||
the bot so I can review what he's been asking and what the bot responded.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- Every interaction from a child user is written to a dedicated audit log, separate from
|
||||
the RSO/memory-scoring logs
|
||||
- Audit log location: `memory_workspace/audit/{username}/YYYY-MM-DD.jsonl`
|
||||
- Each audit entry contains:
|
||||
- ISO timestamp
|
||||
- Username
|
||||
- Full inbound message (not truncated)
|
||||
- Filter action taken (allowed / blocked / flagged)
|
||||
- Filter reason (if blocked/flagged)
|
||||
- Full outbound response
|
||||
- Audit writes are non-blocking (background thread, same pattern as InteractionLogger)
|
||||
- Audit log retention: 365 days (configurable)
|
||||
- Existing RSO interaction logs are not modified — audit log is additive
|
||||
|
||||
---
|
||||
|
||||
### REQ-08 — Configuration-Driven Restricted Users
|
||||
**As a parent**, I want the child safety features to be controlled by config, not hardcoded,
|
||||
so I can add or remove restricted users without modifying Python source.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- A `child_safety` block in `config/adapters.local.yaml` defines which usernames are restricted
|
||||
- Example:
|
||||
```yaml
|
||||
child_safety:
|
||||
restricted_users:
|
||||
- gabriel
|
||||
audit_retention_days: 365
|
||||
```
|
||||
- The `child_safety.py` module reads this config at startup
|
||||
- Adding a new restricted user requires only a config change and bot restart
|
||||
|
||||
---
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
| ID | Requirement |
|
||||
|----|-------------|
|
||||
| NFR-01 | Filtering must add < 50ms latency to message processing |
|
||||
| NFR-02 | Audit log writes must never block response delivery |
|
||||
| NFR-03 | A filter failure (exception) must fail safe — block the message, not pass it |
|
||||
| NFR-04 | Audit log files must not be accessible via any bot tool or command |
|
||||
| NFR-05 | Restricted user config must survive bot restarts |
|
||||
| NFR-06 | False positive rate on game dev questions must be near zero for common Roblox/Lua vocabulary |
|
||||
|
||||
---
|
||||
|
||||
### REQ-09 — Guided Learning Approach (Skill Development Over Answer Delivery)
|
||||
**As a parent**, I want the bot to teach my gabriel how to think and build, not just hand him
|
||||
answers — so that he develops real coding and problem-solving skills over time rather than
|
||||
becoming dependent on the bot.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
|
||||
- The bot's default mode is **guide first, answer second** — not the reverse
|
||||
- Before giving a solution, the bot asks what the user has already tried or what they think
|
||||
might work, unless the question is purely factual ("what does `pairs()` do in Lua?")
|
||||
- When code is provided, it is **always accompanied by an explanation** of what it does and
|
||||
why — never a bare code block with no context
|
||||
- Explanations use the **minimum necessary detail** for his age/level — short, plain-language
|
||||
sentences before diving into code
|
||||
- The bot breaks problems into **smaller steps** and guides through each one rather than
|
||||
solving the whole thing at once:
|
||||
- "Let's tackle the shooting mechanic first. What do you think needs to happen when the
|
||||
player pulls the trigger?"
|
||||
- The bot **celebrates attempts and effort**, not just correct answers:
|
||||
- "Nice — you got the loop right, that's the hard part. The issue is just this one line..."
|
||||
- When the user shares broken code, the bot **guides them to find the bug** rather than
|
||||
pointing straight to it:
|
||||
- "Take a look at line 12 — what do you think that variable is at that point in the loop?"
|
||||
- After giving code, the bot **leaves something for the user to do**:
|
||||
- "I've written the basic function — can you add the part that checks if the player has
|
||||
enough ammo before it fires?"
|
||||
- The bot periodically uses **transfer learning** to connect new concepts to ones already
|
||||
covered:
|
||||
- "Remember the loop we used for the enemy spawner? This is the same idea."
|
||||
- Code IS shown when asked — this is not a Socratic-only mode. The teaching layer wraps
|
||||
the code, it does not replace it.
|
||||
- Purely factual or lookup questions ("what's the Roblox service for detecting player input?")
|
||||
get a direct answer — no forced Socratic preamble for simple lookups.
|
||||
|
||||
---
|
||||
|
||||
### REQ-10 — Token Optimization for Child Sessions
|
||||
**As a parent**, I want Gabriel's sessions to consume as few tokens as possible since he shares
|
||||
the same API pool as me, without degrading the quality of his experience.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
|
||||
- Gabriel's system prompt **skips SOUL.md** (the Garvis homelab persona) — irrelevant to him,
|
||||
currently costs ~935 tokens per turn
|
||||
- Gabriel's system prompt **skips context.md** (SSH hosts, Proxmox VMs, networking) — entirely
|
||||
irrelevant to Lua help, currently costs ~227 tokens per turn
|
||||
- Gabriel's system prompt uses a **lightweight tutor identity block** (~100 tokens) in place
|
||||
of SOUL.md — enough to set tone without the homelab baggage
|
||||
- The **hybrid memory search is skipped** for Gabriel — the memory store is Jordan's homelab
|
||||
operational data and returns irrelevant chunks that waste tokens
|
||||
- Gabriel's **conversation history window is capped at 10 messages** (vs Jordan's 20) — Lua
|
||||
help sessions rarely need deep context; this roughly halves history token cost
|
||||
- The **delegation/sub-agent block** is omitted from Gabriel's system prompt — he will never
|
||||
trigger multi-agent tasks (~80 tokens saved)
|
||||
- All optimizations are conditional on `is_restricted(username)` — Jordan's experience is
|
||||
completely unchanged
|
||||
|
||||
**Expected savings per Gabriel turn:**
|
||||
|
||||
| Removed component | Token saving |
|
||||
|---|---|
|
||||
| SOUL.md | ~935 |
|
||||
| context.md | ~227 |
|
||||
| Memory search (5 chunks avg) | ~300–500 |
|
||||
| History window 20→10 (avg) | ~20–50% of history |
|
||||
| Delegation block | ~80 |
|
||||
| **Total** | **~1,500–1,800 tokens/turn** |
|
||||
|
||||
---
|
||||
|
||||
### REQ-11 — AI Literacy as Part of the Teaching Approach
|
||||
**As a parent**, I want the bot to teach Gabriel how to use AI tools well — not just what to
|
||||
ask, but how to ask — so he builds self-sufficiency with these tools rather than dependency.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
|
||||
- When Gabriel asks a vague or broad question, the bot **models good question-asking** by
|
||||
clarifying its understanding before answering:
|
||||
> "Just to make sure I give you the most useful answer — you want the enemy to deal damage
|
||||
> on touch, right? Or is it supposed to chase first?"
|
||||
- When Gabriel notices the bot "forgot" something earlier, the bot **explains context windows**
|
||||
in plain terms, naturally:
|
||||
> "Yeah — I can only hold so much of our conversation in memory at once. At the start of
|
||||
> next session, just remind me what you're building and I'll be straight back up to speed."
|
||||
- The bot **teaches the ideal coding question format** when the opportunity arises naturally:
|
||||
> "Next time try: what your code does now, what you want it to do, and what you've already
|
||||
> tried. That combo gets you a much faster answer."
|
||||
- The bot **flags its own assumptions** so Gabriel learns to spot ambiguity:
|
||||
> "I'm assuming you want this to reset on respawn — let me know if that's not right."
|
||||
- AI literacy is woven into responses naturally — never a separate lecture unless Gabriel
|
||||
directly asks how the bot works.
|
||||
|
||||
---
|
||||
|
||||
### REQ-12 — Cross-Session Project Continuity
|
||||
**As a parent**, I want the bot to remember what Gabriel is building between sessions so he
|
||||
doesn't have to re-explain his project every time, and the teaching approach stays coherent
|
||||
over days and weeks — not just within a single conversation.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
|
||||
- A lightweight project context file exists at `memory_workspace/users/gabriel_context.md`
|
||||
- This file is injected into Gabriel's system prompt on every turn (replaces memory search,
|
||||
which is skipped for Gabriel per REQ-10)
|
||||
- The bot updates `gabriel_context.md` at the end of each session with a brief summary of:
|
||||
- What Gabriel is currently building (project name/description)
|
||||
- What was worked on in this session (features, bugs fixed, concepts covered)
|
||||
- Any open threads or "next steps" Gabriel mentioned
|
||||
- Any new concepts introduced this session (feeds into REQ-13)
|
||||
- The update is concise — target < 30 lines total; the file is overwritten, not appended
|
||||
- On first session (file doesn't exist), the bot starts fresh and creates it after the
|
||||
first substantive exchange
|
||||
- The file is human-readable so Jordan can review it directly in Slack's file system or
|
||||
the memory workspace
|
||||
|
||||
---
|
||||
|
||||
### REQ-13 — Skill Progression Tracking
|
||||
**As a parent**, I want the bot to remember what Gabriel has already been taught so it doesn't
|
||||
re-explain concepts he's mastered, and can reference them naturally when introducing related ideas.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
|
||||
- A skills log section exists within `gabriel_context.md` (same file as REQ-12, separate section)
|
||||
- Each entry records: concept name, brief description, date first introduced
|
||||
- Example entries:
|
||||
- `for loops` — iterating over tables, introduced 2026-04-21
|
||||
- `functions` — defining and calling, parameters vs arguments, introduced 2026-04-22
|
||||
- `RemoteEvents` — client-server communication in Roblox, introduced 2026-04-25
|
||||
- The bot checks this log before explaining a concept — if already introduced, it references
|
||||
it rather than re-explaining from scratch:
|
||||
> "You've used this before — remember the loop we wrote for the enemy spawner?"
|
||||
- The log grows over time; the bot adds an entry the first time it meaningfully teaches a new
|
||||
concept, not for every mention
|
||||
- Skills log is appended to `gabriel_context.md` under a `## Skills Introduced` heading
|
||||
|
||||
---
|
||||
|
||||
### REQ-14 — First-Run Onboarding Experience
|
||||
**As a parent**, I want Gabriel to receive a friendly welcome the first time he messages the
|
||||
bot that sets expectations — what it can help him with, how it works, and that it's there
|
||||
to teach him, not do the work for him.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
|
||||
- The bot detects a first-run state by checking whether `gabriel_context.md` exists
|
||||
- On first message from Gabriel, before processing his question, the bot sends a welcome
|
||||
message that covers:
|
||||
- What it can help with (Lua, Roblox Studio, game design, coding questions)
|
||||
- How the teaching approach works — that it'll guide him and ask questions, not just
|
||||
hand over answers ("I'm here to help you figure it out, not just give you the answer")
|
||||
- That it'll remember his projects between sessions
|
||||
- An invitation to tell it what he's working on
|
||||
- The welcome is sent as a separate message before the response to his first question
|
||||
- The welcome is conversational and age-appropriate — not a terms-and-conditions wall
|
||||
- After the welcome, his first actual question is answered normally
|
||||
- The first-run check only fires once; subsequent sessions go straight to his question
|
||||
|
||||
---
|
||||
|
||||
### REQ-15 — Slack Allow-List (Gap Fix)
|
||||
**As a parent**, I want only authorised users to be able to message the bot on Slack, since
|
||||
the Slack adapter currently processes messages from any workspace member with no restriction.
|
||||
|
||||
**Acceptance Criteria:**
|
||||
|
||||
- The Slack adapter checks an `allowed_users` list from config before processing any message
|
||||
- Messages from users not on the allow-list are silently dropped (no response sent)
|
||||
- The allow-list is read from `config/adapters.local.yaml` under the slack adapter settings,
|
||||
matching the pattern already used by the Slack adapter for other config
|
||||
- Jordan's existing Slack user ID remains on the list; Gabriel's is added
|
||||
- No change to Telegram adapter behaviour (already has this check)
|
||||
|
||||
---
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Time-of-day restrictions (not enforceable at bot level — use Slack parental controls)
|
||||
- Per-topic whitelists managed via chat commands
|
||||
- Automated parent notifications on blocked requests (future enhancement)
|
||||
- Web dashboard for audit log review (future enhancement)
|
||||
Reference in New Issue
Block a user