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
16 KiB
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) inadapters.local.yaml - His username appears in the
allowed_userslist - 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 configuredRESTRICTED_USERSlist
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_safetyblock inconfig/adapters.local.yamldefines which usernames are restricted - Example:
child_safety: restricted_users: - gabriel audit_retention_days: 365 - The
child_safety.pymodule 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.mdat 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-21functions— defining and calling, parameters vs arguments, introduced 2026-04-22RemoteEvents— 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.mdunder a## Skills Introducedheading
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.mdexists - 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_userslist 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.yamlunder 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)