Janitor Script Builder
Advanced scripts made easy – fill out simple forms, get copy-paste-ready code.
Stateless 101: Understanding How Scripts Work
Key Concept: JanitorAI scripts run fresh on every single message. Variables don't persist between messages unless you store them in scenario/personality notes.
var score = 0; score++;
Score resets to 0 every message
Memory → adds to scenario notes
Scenario persists between messages
Using {{char}} tags for variables
Fragile, can break with updates
Pro Tip: Scripts only check the latest user message by default. To check history, you need experimental methods (which may break).
Pre-Launch Test Checklist
Before using your script in JanitorAI:
- Enable Debug Mode in Module Control Panel for first test
- Start with 1-2 modules, add more once working
- Test each trigger keyword/phrase in a real conversation
- Check scenario notes after 5-10 messages for bloat
- Verify message_count increments correctly (rerolls don't count)
- Disable debug mode before final deployment
- Keep total script under 10,000 characters for best performance
Recommended Build Order (Pro Workflow)
Follow this order for the most reliable and maintainable scripts:
- Lorebook → Foundation for rich context (most stable)
- Memory System → Track user info (stable)
- Pacing → Gate story progression (stable)
- Tone/State Engine → Dynamic mood shifts (stable)
- Time & Environment → Hour-based behaviors (stable)
- Ambient Events → Add flavor (watch token growth)
- Random Events → Weighted reactions (moderate complexity)
- Combined Conditions → Multi-trigger rules (advanced)
- Scoring (Stateless only) → Sentiment analysis (experimental)
Scenario Maintenance Best Practices
Pro strategies to prevent bloat:
- Use personality for moods/states instead of scenario (personality can be overwritten)
- Summarize old notes periodically instead of endless appending
- Use lorebooks for static info that only triggers when relevant
- Prefer "replace" over "append" for things that change (time, mood)
- Test scenario length after 20-30 messages and clean if needed
Module Control Panel
Lorebook (Hierarchical Keyword Database)
Create a rich world with people, places, objects, moods, and events that trigger based on keywords.
Lore Entries
- Keywords too broad (e.g., "is", "the") trigger constantly
- Entries too long cause token bloat
- Without break-early, multiple entries can fire and overwhelm context
- Not using padded matching causes false triggers on partial words
- Same entry can trigger repeatedly → enable deduplication below
Lorebook Glossary
- Keywords
- Words that trigger this lore entry (comma-separated, case-insensitive)
- Category
- Organizes entries: people, places, objects, moods, events
- Content
- Text injected into scenario when keywords match
- Padded Matching
- Requires spaces around keywords to avoid "cat" matching "scatter"
- Break-Early
- Stops checking after first match (recommended for performance)
Memory System
Automatically detect and remember the user's name, facts about them, likes, and dislikes.
- Trigger phrases too specific → never fire
- No deduplication → same fact saved multiple times (v3 includes basic dedupe)
- Scenario grows forever without maintenance
- Name regex may miss very long names (limited to 40 chars for safety)
Pacing System (Message Count Gates)
Control story progression based on how many messages have been sent.
Message Count Phases
One-Time Events (Exact Message Count)
- Forgetting that rerolls don't increment message_count
- Overlapping phases causing conflicts
- One-time events at count 1 may miss if bot speaks first
Pacing Glossary
- message_count
- Built-in JanitorAI variable tracking total user messages sent (rerolls don't increment)
- Phases
- Ranges of messages (e.g., 1-10, 11-30) with associated behavior
- One-Time Events
- Fire exactly once at a specific message number
Tone/State Engine
Dynamically shift character personality based on keywords in user messages.
Tone Triggers
- Without padded matching, "sad" triggers on "salad"
- Multiple triggers fire → personality bloats
- Mood doesn't reset between messages (use replace, not append)
Keywords:
angry, mad, furiousPersonality Add-on:
{{char}} is currently angry and speaking tersely.
Time & Environment System
Change character behavior and environment based on time of day.
Time-Based Behaviors
- Server time may not match your local time without offset
- Overlapping time slots cause conflicts
- Hour-based checks only update once per hour
- Forgot to handle wrap-around (e.g., 22:00-03:00) → v3 handles this automatically
Ambient Events (Random Flavor Text)
Add random environmental details to make the world feel alive.
Ambient Event Pool
- High probability (>20%) causes rapid scenario bloat
- Events append forever without cleanup
- Same event can trigger multiple times (expected behavior)
A bird chirps in the distance. The cafe smells of fresh coffee.
Random Events (Weighted Reactions)
Trigger random character reactions when user says specific phrases.
Event Triggers
- Trigger phrases too common → fires constantly
- Responses not pipe-separated correctly
- Adding to personality instead of scenario
Trigger Phrase:
what do you thinkResponses:
I think it's interesting|I'm not sure|That's a tough one (pipe-separated, chosen randomly)
Combined Conditions (Multi-Trigger Rules)
Create rules that fire when multiple conditions are met (keywords + time + message count).
Combined Rules
- Conditions too strict → never triggers
- Time checks without timezone offset mismatch user's local time
- Multiple rules fire at once causing bloat
Keywords:
romantic, dinnerMin Hour:
18 Max Hour: 22Min Messages:
20Result:
{{char}} suggests a romantic candlelit dinner.→ Only fires if user mentions "romantic" or "dinner" between 6pm-10pm after 20+ messages
Scoring Engine (EXPERIMENTAL)
Persistent: Uses {{char}} tags to store scores (fragile, may break with platform updates)
Positive Keywords
Negative Keywords
Score Thresholds & Responses
- Persistent mode tags can be stripped by platform updates
- Keyword sentiment too simplistic for nuanced emotion
- Score thresholds never reached with stateless mode
- No decay → persistent scores grow forever
Script Tester
Test your generated script with sample messages to verify triggers work correctly before deploying to JanitorAI.
context.chat.last_messagecontext.character.name if your script uses it- Generate your script first in the relevant tab before testing
- Test edge cases: keywords with punctuation, different capitalizations
- Try messages that should NOT trigger to verify specificity
- Check console output for any errors or debug logs from your script
Trigger Analyzer
Scan all modules for potential keyword conflicts, overlaps, and bottlenecks.
Final Combined Output
This is the complete script with all enabled modules merged in your chosen order.