# 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)