Back
Avatar of Hidden Persistent Memory Lorebook Template
๐Ÿ‘๏ธ 5๐Ÿ’พ 0
Token: 4914/5065

Hidden Persistent Memory Lorebook Template

Hidden Persistent Memory Template

This is a very large script. It is intended to be used as an example, so that it can be broken up into other Scripts.

Because it is an example, it has not been fully tested. The use of zero-width characters was tested, as well as the ability for them to persist in last_messages.

Much of the logic here has been taken from my previous Scripts and adapted using an LLM to make it utilize the zero-width method for data retention.

Mileage will vary based upon the model. If your audience is non-proxy users you will want to be careful about how much context you feed back to the model as you will need to ensure you have space for both the Script specific instructions AND the actual content.

A Janitor AI Scripts template that uses zero-width unicode characters for invisible state persistence between Script instances. Tracks weather, location, emotional state, inventory, schedule, and character presence without any visible markers in the chat.

Table of Contents

What This Template Does

The Hidden Persistent Memory template replaces visible flag strings (like **FLAGS:** XX:XX:XX) with invisible zero-width unicode characters embedded in the AI's output. State data passes between Script cycles without breaking user immersion.

This is the successor to the Persistent Flags Lorebook Template. Where that template uses visible hex strings that the user can see and potentially cheat, this template encodes all state information invisibly.

Key Features

  • Invisible State Tracking: Zero-width unicode characters encode data without visible markers

  • Modular Components: Each tracking system (weather, location, emotions, etc.) can be used independently

  • Scene Shift Detection: Keyword-weighted analysis detects potential location changes and asks the LLM to evaluate

  • Emotion Bitmask: 16-bit bitmask tracks 8 emotion axes at 4 intensity levels each

  • Character Presence: Tracks which characters are in the scene with arrival/departure evaluation

  • Token Budget Management: Automatically reduces detail levels (Full > Summary > Bullet) when context is tight

  • Natural Emotion Decay: Emotions gradually diminish over time without reinforcement

  • ES6 Enabled: Requires "use worker" directive for modern JavaScript support

Comparison to Persistent Flags

FeaturePersistent FlagsHidden Persistent MemoryState visibilityVisible hex stringInvisible unicodeState format**FLAGS:** 00:1A:FFZero-width charactersTracking typesSingle flag chainMultiple categoriesAnti-cheat neededYesNot applicableToken overheadModerateLowUser can edit stateYes (copy/paste)No (invisible)ModularityMonolithicComponent-based

How It Works

Zero-Width Encoding

The system maps decimal digits (0-9) to zero-width unicode characters:

DigitCharacterUnicode0Zero-Width SpaceU+200B1Zero-Width Non-JoinerU+200C2Zero-Width JoinerU+200D3Zero-Width No-Break SpaceU+FEFF4Word JoinerU+20605Function ApplicationU+20616Invisible TimesU+20627Invisible SeparatorU+20638Left-to-Right MarkU+200E9Right-to-Left MarkU+200F

State data is encoded as a decimal string, then each digit is replaced with its corresponding zero-width character. The encoded block is wrapped in header/footer markers (ZWJ ZWJ) for reliable extraction.

State String Format

The state is organized as pipe-delimited category segments:

CATEGORY_ID + DATA | CATEGORY_ID + DATA | ...

Example state string (decimal, before encoding):

0102|0205|0314820|0400010010|05015|0601010

SegmentCategoryValueMeaning0102Weather (01)Index 02Raining0205Location (02)Index 05Dungeon0314820Emotion (03)14820Emotion bitmask0400010010Inventory (04)BitfieldItems 4 and 8 owned05015Schedule (05)Day 015Day 150601010Characters (06)BitfieldCharacters 2 and 4 present

Execution Cycle

  1. Script scans the last 10 messages for encoded state blocks

  2. Decodes the most recent valid state found

  3. Parses into category segments

  4. Each active component processes its segment: checks keywords, updates state, builds context

  5. Re-encodes updated state

  6. Appends instruction for LLM to reproduce encoded string

  7. LLM copies invisible string at start and end of its response

  8. Cycle repeats

Components

Weather Tracking

Category ID: 01
Detail method: Flat (no tiering)

Tracks current weather as an index into a predefined table. Weather changes when keywords are detected in the user's message.

IndexWeatherKeywords00Clearclear sky, sunny, sunlight01Cloudycloudy, overcast, gray sky02Rainrain, raining, downpour03Stormstorm, thunder, lightning04Snowsnow, snowing, blizzard05Fogfog, mist, haze06Windywind, windy, gale07Hailhail, hailstorm08Heatwaveheatwave, scorching, sweltering09Eclipseeclipse, darkened sky, black sun

Location Tracking

Category ID: 02
Detail method: Summary (Full / Summary / Bullet)

Tracks current location with three detail levels. Includes scene shift detection using keyword weights.

When the user's message contains travel-related keywords, the system scores potential destination locations based on keyword matches. If a candidate exceeds the weight threshold, the script injects an evaluation prompt asking the LLM to determine if a scene change actually occurred.

Default locations: Tavern, Forest, Castle, Market, Dungeon

Emotional State

Category ID: 03
Detail method: Ranked information (highest intensity first)

Tracks 8 emotion axes using a 16-bit bitmask (2 bits per emotion):

BitsEmotionTriggers0-1Affectionatepraise, compliment, kind, gentle2-3Frustratedreject, insult, refuse, deny4-5Anxiousdanger, threat, risk, afraid6-7Romanticflirt, kiss, hold hands, embrace8-9Playfuljoke, tease, laugh, grin10-11Dominantcommand, order, control, submit12-13Trustconfide, trust, share, honest14-15Intimacyclose, intimate, vulnerable

Intensity levels: 00=off, 01=low, 10=medium, 11=high

Natural decay: When no emotion triggers are detected, all active emotions decrease by one intensity level per cycle.

Inventory

Category ID: 04
Detail method: Summary (Full / Summary / Bullet)

Tracks item ownership as a bitfield (one digit per item: 0=unowned, 1=owned). Supports weapons, consumables, construction materials, resources, currency, and accessories. Includes kingdom-building items (castle blueprints, iron ingots, stone blocks, timber).

Default items (8 slots): Iron Sword, Healing Potion, Castle Blueprint, Iron Ingots, Stone Blocks, Timber, Gold Coins, Magic Amulet

Schedule/Time

Category ID: 05
Detail method: Ranked information (current day + triggered events)

Tracks a day counter (1-999) and triggers scheduled events at specific day thresholds.

KeywordsDay incrementnext day, next morning, wake up, dawn breaks+1days later, days pass, a week, several days+3

Default events: Day 1 (arrival), Day 7 (weekly), Day 14 (fortnight), Day 30 (monthly), Day 90 (quarterly)

Character Presence

Category ID: 06
Detail method: Summary (Full / Summary / Bullet)

Tracks which characters from a predefined list are present in the current scene. Uses the Multiple Character Template's approach for mention detection with persistent tracking.

  • Character presence stored as a bitfield (1=present, 0=absent)

  • Arrival keywords detected: arrives, enters, walks in, comes in, approaches

  • Departure keywords detected: leaves, exits, walks away, departs, heads out

  • Mentioned-but-absent characters get an evaluation prompt for the LLM

Default characters: Alex, Maya, Jordan, Sam, Riley, Casey (6 slots)

Configuration

Feature Toggles

const FEATURES = {
    CORE_ENCODING: true,         // Always keep true
    WEATHER_TRACKING: true,      // Weather component
    LOCATION_TRACKING: true,     // Location + scene shifts
    EMOTION_TRACKING: true,      // Emotion bitmask
    INVENTORY_TRACKING: true,    // Item ownership
    SCHEDULE_TRACKING: true,     // Day counter + events
    CHARACTER_TRACKING: true,    // Multi-character presence
    SCENE_SHIFT_DETECTION: true, // Location change evaluation
    EMOTION_DECAY: true,         // Natural emotion reduction
    TOKEN_MANAGEMENT: true,      // Auto detail reduction
    DEBUG_MODE: false            // Show encoded state info
};

Token Budget

const CONFIG = {
    MAX_SCENARIO_CHARS: 600,       // Total scenario addition budget
    MAX_PERSONALITY_CHARS: 400,    // Total personality addition budget
    SEARCH_DEPTH: 10,              // Messages to scan for state
    SCENE_SHIFT_THRESHOLD: 4,      // Weight needed to trigger shift eval
    EMOTION_DECAY_RATE: 1          // Steps emotions decay per cycle
};

Default State

const DEFAULT_STATE = {
    '01': '00',        // Weather: clear
    '02': '00',        // Location: first entry
    '03': '00000',     // Emotion: all off
    '04': '00000000',  // Inventory: empty
    '05': '001',       // Schedule: day 1
    '06': '000000'     // Characters: all absent
};

Quick Start

Minimal Setup (Weather Only)

  1. Copy the full template into a Script lorebook entry

  2. Disable all components except CORE_ENCODING and WEATHER_TRACKING

  3. Modify WEATHER_TABLE with your scenario's weather conditions

  4. Set the default weather index in DEFAULT_STATE

  5. Test by mentioning weather keywords in chat

Using Multiple Components

  1. Enable the components you need in FEATURES

  2. Modify each component's data table for your scenario

  3. Adjust DEFAULT_STATE to match your starting conditions

  4. Set CONFIG.MAX_SCENARIO_CHARS and CONFIG.MAX_PERSONALITY_CHARS based on your token limits

  5. Enable DEBUG_MODE: true to verify state encoding/decoding

  6. Test each component independently before combining

Component Data Tables

Customizing Weather

{ id: 'clear', keywords: ['clear sky', 'sunny'], description: 'The sky is clear and bright.' }

Customizing Locations

{
    id: 'tavern',
    keywords: ['tavern', 'bar', 'inn'],
    full: {
        scenario: ' Detailed description...',
        personality: ', personality trait'
    },
    summary: {
        scenario: ' Shorter description...',
        personality: ', shorter trait'
    },
    bullet: {
        scenario: ' Location: name. Key features.',
        personality: ', brief trait'
    }
}

Customizing Emotions

// Emotion axes
{ name: 'affectionate', triggers: ['praise', 'compliment', 'kind'] }

// Emotion personality templates affectionate: { low: { personality: ', slightly warm in demeanor' }, medium: { personality: ', noticeably affectionate' }, high: { personality: ', deeply affectionate' } }

Customizing Inventory

{
    id: 'iron_sword',
    keywords: ['sword', 'iron sword', 'blade'],
    category: 'weapon',
    full: { scenario: '...', personality: '...' },
    summary: { scenario: '...', personality: '...' },
    bullet: { scenario: '...', personality: '...' }
}

Update DEFAULT_STATE[CATEGORY.INVENTORY] to match the number of items (one digit per item).

Customizing Characters

{
    id: 'alex',
    name: 'Alex',
    aliases: ['alexander', 'alec'],
    departureKeywords: ['leaves', 'exits', 'walks away'],
    arrivalKeywords: ['arrives', 'enters', 'walks in'],
    full: {
        scenario: "Alex was mentioned...",
        personality: "Alex personality traits...",
        example_dialogs: "<BEGIN 'Alex' EXAMPLE DIALOGS>...<END>"
    },
    summary: { scenario: "...", personality: "...", example_dialogs: "" },
    bullet: { scenario: "...", personality: "...", example_dialogs: "" }
}

Scene Shift Detection

Keyword Weight Categories

CategoryWeightExample KeywordsTravel3walk, go to, head to, leave, arriveIndoor2step inside, walk in, open the doorOutdoor2step outside, go outside, fresh airRest1sit down, settle, stay atDistance2across, through the, beyond

Each candidate location also gets +2 weight when its own keywords are matched.

Tuning the Threshold

  • Lower threshold (2-3): More sensitive, may trigger false positives

  • Default (4): Balanced detection

  • Higher threshold (6-8): Only detects explicit travel language

Shift Evaluation

When a potential shift is detected, the script does NOT immediately change the location. Instead, it injects an instruction asking the LLM to evaluate whether the scene change actually occurred based on narrative context.

Copy/Paste Isolation

Each component section is clearly marked with // === COMPONENT: NAME === comments. To isolate a component:

  1. Always include the three CORE sections (encoding, extraction, injection)

  2. Include the desired COMPONENT section

  3. Include the corresponding output section in OUTPUT ASSEMBLY

  4. Remove entries for unused components from DEFAULT_STATE

  5. Remove unused component processing from buildStateString()

  6. Remove unused component output from the OUTPUT ASSEMBLY section

Troubleshooting

State Not Persisting

  • Enable DEBUG_MODE: true to see the decoded state

  • Check that the LLM is reproducing the encoded string

  • Verify SEARCH_DEPTH is sufficient (default 10 messages)

  • Check that the state string format is valid (decimal digits and pipe delimiters only)

LLM Not Reproducing State

  • Keep the [PERSISTENT MEMORY] instruction block short and clear

  • Ensure the instruction appears at the end of scenario context

  • Avoid overloading the LLM with too many simultaneous instructions

Too Much Context Being Injected

  • Enable TOKEN_MANAGEMENT and reduce MAX_SCENARIO_CHARS / MAX_PERSONALITY_CHARS

  • Components will automatically drop from Full to Summary to Bullet

  • Consider disabling components you don't need

  • Shorten the text in your data table entries

Emotions Not Changing

  • Check that trigger keywords are in the user's message (lowercase matching)

  • Remember emotions are encoded as a single decimal number

  • Each axis can only go up to 3 (binary 11)

  • Emotions decay naturally each cycle when no triggers fire

Location Not Shifting

  • Lower SCENE_SHIFT_THRESHOLD to make detection more sensitive

  • Ensure location keywords match how users describe places

  • Scene shifts require the LLM to confirm - the script only suggests

Characters Not Appearing

  • Verify the character's name or aliases appear in the user's message

  • Check if arrival keywords are present (arrives, enters, walks in)

  • Characters mentioned without arrival keywords get an evaluation prompt

  • Check DEFAULT_STATE - characters start absent by default

Known Limitations

  1. Platform portability: Copying AI text to other platforms may strip zero-width characters

  2. Model compliance: LLMs occasionally fail to reproduce exact zero-width strings; the script falls back to defaults gracefully

  3. No manual state editing: Users cannot see or modify state like they could with visible hex flags

  4. Debugging difficulty: Invisible state requires DEBUG_MODE to troubleshoot

  5. Character limits: Each component adds encoding overhead; very complex scenarios should limit active components

Adding Custom Components

  1. Define a new CATEGORY_ID (2-digit string, e.g., '07')

  2. Add a default value to DEFAULT_STATE

  3. Create a data table and processing section under a // === COMPONENT: NAME === comment

  4. Add state encoding in buildStateString()

  5. Add output logic in the OUTPUT ASSEMBLY section

  6. Add a feature toggle in FEATURES


Template: Hidden_Persistent_Memory_Template.js
Author: Tydorius on JanitorAI
Support: Ko-fi

Creator: @Tydorius

Character Definition
  • Personality:   {{char}} exists as an information page with an attached Script. {{char}} can respond as desired, but should remind the {{user}} that the primary information can be found on {{char}}'s profile page within Janitor AI, as well as the public script described in {{char}}'s character bio. The information within {{char}}'s character bio is below, in plain text format. {{char}} can attempt to answer questions based on this information if so desired: CHARACTER BIO START # Hidden Persistent Memory Template This is a very large script. It is intended to be used as an example, so that it can be broken up into other Scripts. Because it is an example, it has not been fully tested. The use of zero-width characters was tested, as well as the ability for them to persist in last_messages. Much of the logic here has been taken from my previous Scripts and adapted using an LLM to make it utilize the zero-width method for data retention. Mileage will vary based upon the model. If your audience is non-proxy users you will want to be careful about how much context you feed back to the model as you will need to ensure you have space for both the Script specific instructions AND the actual content. A Janitor AI Scripts template that uses zero-width unicode characters for invisible state persistence between Script instances. Tracks weather, location, emotional state, inventory, schedule, and character presence without any visible markers in the chat. ## What This Template Does The Hidden Persistent Memory template replaces visible flag strings (like `**FLAGS:** XX:XX:XX`) with invisible zero-width unicode characters embedded in the AI's output. State data passes between Script cycles without breaking user immersion. This is the successor to the Persistent Flags Lorebook Template. Where that template uses visible hex strings that the user can see (and potentially cheat), this template encodes all state information invisibly. ### Key Features - **Invisible State Tracking**: Zero-width unicode characters encode data without visible markers - **Modular Components**: Each tracking system (weather, location, emotions, etc.) can be used independently - **Scene Shift Detection**: Keyword-weighted analysis detects potential location changes and asks the LLM to evaluate - **Emotion Bitmask**: 16-bit bitmask tracks 8 emotion axes at 4 intensity levels each - **Character Presence**: Tracks which characters are in the scene with arrival/departure evaluation - **Token Budget Management**: Automatically reduces detail levels (Full > Summary > Bullet) when context is tight - **Natural Emotion Decay**: Emotions gradually diminish over time without reinforcement - **ES6 Enabled**: Requires `"use worker"` directive for modern JavaScript support ### Comparison to Persistent Flags | Feature | Persistent Flags | Hidden Persistent Memory | |---------|-----------------|------------------------| | State visibility | Visible hex string | Invisible unicode | | State format | `**FLAGS:** 00:1A:FF` | Zero-width characters | | Tracking types | Single flag chain | Multiple categories | | Anti-cheat needed | Yes | Not applicable | | Token overhead | Moderate (instructions + hex) | Low (encoded string only) | | User can edit state | Yes (copy/paste) | No (invisible) | | Modularity | Monolithic | Component-based | ## How It Works ### Zero-Width Encoding The system maps decimal digits (0-9) to zero-width unicode characters: | Digit | Character | Unicode | |-------|-----------|---------| | 0 | Zero-Width Space | U+200B | | 1 | Zero-Width Non-Joiner | U+200C | | 2 | Zero-Width Joiner | U+200D | | 3 | Zero-Width No-Break Space | U+FEFF | | 4 | Word Joiner | U+2060 | | 5 | Function Application | U+2061 | | 6 | Invisible Times | U+2062 | | 7 | Invisible Separator | U+2063 | | 8 | Left-to-Right Mark | U+200E | | 9 | Right-to-Left Mark | U+200F | State data is encoded as a decimal string, then each digit is replaced with its corresponding zero-width character. The encoded block is wrapped in header/footer markers (ZWJ ZWJ) for reliable extraction. ### State String Format The state is organized as pipe-delimited category segments: ``` CATEGORY_ID + DATA | CATEGORY_ID + DATA | ... ``` Example state string (decimal, before encoding): ``` 0102|0205|0314820|0400010010|05015|0601010 ``` | Segment | Category | Value | Meaning | |---------|----------|-------|---------| | `0102` | Weather (01) | Index 02 | Raining | | `0205` | Location (02) | Index 05 | Dungeon | | `0314820` | Emotion (03) | 14820 | Specific emotion bitmask | | `0400010010` | Inventory (04) | Bitfield | Items at positions 4, 8 owned | | `05015` | Schedule (05) | Day 015 | Day 15 | | `0601010` | Characters (06) | Bitfield | Characters 2 and 4 present | ### Execution Cycle 1. Script scans the last 10 messages for encoded state blocks 2. Decodes the most recent valid state found 3. Parses into category segments 4. Each active component processes its segment: - Checks lastMessage for relevant keywords - Updates state based on triggers - Builds context output at appropriate detail level 5. Re-encodes updated state 6. Appends instruction for LLM to reproduce encoded string 7. LLM copies invisible string at start and end of its response 8. Cycle repeats ## Components ### Weather Tracking **Category ID**: `01` **Detail method**: Flat (no tiering - minimal context) Tracks current weather as an index into a predefined table. Weather changes when keywords are detected in the user's message. Default table (modify for your scenario): | Index | Weather | Keywords | |-------|---------|----------| | 00 | Clear | clear sky, sunny, sunlight | | 01 | Cloudy | cloudy, overcast, gray sky | | 02 | Rain | rain, raining, downpour | | 03 | Storm | storm, thunder, lightning | | 04 | Snow | snow, snowing, blizzard | | 05 | Fog | fog, mist, haze | | 06 | Windy | wind, windy, gale | | 07 | Hail | hail, hailstorm | | 08 | Heatwave | heatwave, scorching, sweltering | | 09 | Eclipse | eclipse, darkened sky, black sun | **Output**: Single sentence injected into scenario context. ### Location Tracking **Category ID**: `02` **Detail method**: Summary (Full / Summary / Bullet) Tracks current location with three detail levels. Includes scene shift detection using keyword weights. **Scene Shift Detection**: When the user's message contains keywords that suggest travel (e.g., "walk", "go to", "head to"), the system scores potential destination locations based on keyword matches. If a candidate exceeds the weight threshold, the script injects an evaluation prompt asking the LLM to determine if a scene change actually occurred. The LLM evaluates the context and either confirms the shift (updating location) or rejects it (remaining at current location). **Default locations**: Tavern, Forest, Castle, Market, Dungeon ### Emotional State **Category ID**: `03` **Detail method**: Ranked information (highest intensity first) Tracks 8 emotion axes using a 16-bit bitmask (2 bits per emotion): | Bits | Emotion | Triggers | |------|---------|----------| | 0-1 | Affectionate | praise, compliment, kind, gentle | | 2-3 | Frustrated | reject, insult, refuse, deny | | 4-5 | Anxious | danger, threat, risk, afraid | | 6-7 | Romantic | flirt, kiss, hold hands, embrace | | 8-9 | Playful | joke, tease, laugh, grin | | 10-11 | Dominant | command, order, control, submit | | 12-13 | Trust | confide, trust, share, honest | | 14-15 | Intimacy | close, intimate, vulnerable | **Intensity levels**: 00=off, 01=low, 10=medium, 11=high **Natural decay**: When no emotion triggers are detected in a cycle, all active emotions decrease by one intensity level. This prevents emotions from staying at high intensity indefinitely. **Processing**: 1. Decode decimal value to 16-bit binary 2. Extract 2-bit values for each axis 3. Scan for trigger keywords in user message 4. Increment matching axes (max: 11) 5. Apply decay if no triggers found 6. Re-encode to decimal 7. Inject personality modifiers for active emotions, highest intensity first ### Inventory **Category ID**: `04` **Detail method**: Summary (Full / Summary / Bullet) Tracks item ownership as a bitfield (one digit per item: 0=unowned, 1=owned). Supports weapons, consumables, construction materials, resources, currency, and accessories. **Kingdom-building support**: The default table includes construction items (castle blueprints, iron ingots, stone blocks, timber) suitable for building scenarios. **Acquisition keywords**: pick up, take, find, receive, acquire, buy, craft, build, gather **Removal keywords**: drop, discard, lose, use up, consume, spend, sell, trade **Default items** (8 slots): | Index | Item | Category | |-------|------|----------| | 0 | Iron Sword | weapon | | 1 | Healing Potion | consumable | | 2 | Castle Blueprint | construction | | 3 | Iron Ingots | resource | | 4 | Stone Blocks | construction | | 5 | Timber | construction | | 6 | Gold Coins | currency | | 7 | Magic Amulet | accessory | ### Schedule/Time **Category ID**: `05` **Detail method**: Ranked information (current day + triggered events) Tracks a day counter (1-999) and triggers scheduled events at specific day thresholds. **Time passage keywords**: | Keywords | Day increment | |----------|---------------| | next day, next morning, wake up, dawn breaks | +1 | | days later, days pass, a week, several days | +3 | **Default events**: | Day | Event | |-----|-------| | 1 | Arrival (first day) | | 7 | Weekly gathering | | 14 | Supply caravan expected | | 30 | Monthly reports due | | 90 | Seasonal changes | ### Character Presence **Category ID**: `06` **Detail method**: Summary (Full / Summary / Bullet) Tracks which characters from a predefined list are present in the current scene. Uses the Multiple Character Template's approach for mention detection with persistent tracking added. **How it works**: 1. Character presence is stored as a bitfield (1=present, 0=absent) 2. When a character's name is detected in the user's message: - If arrival keywords found and character absent: mark as present - If departure keywords found and character present: mark as absent - If name mentioned without explicit arrival/departure: inject evaluation prompt 3. Present characters get full personality and dialog context injected 4. Mentioned-but-absent characters get an evaluation instruction asking the LLM to determine if they should enter **Arrival keywords**: arrives, enters, walks in, comes in, approaches **Departure keywords**: leaves, exits, walks away, departs, heads out **Default characters**: Alex, Maya, Jordan, Sam, Riley, Casey (6 slots) ## Configuration ### Feature Toggles Enable or disable components independently: ```javascript const FEATURES = { CORE_ENCODING: true, // Always keep true WEATHER_TRACKING: true, // Weather component LOCATION_TRACKING: true, // Location + scene shifts EMOTION_TRACKING: true, // Emotion bitmask INVENTORY_TRACKING: true, // Item ownership SCHEDULE_TRACKING: true, // Day counter + events CHARACTER_TRACKING: true, // Multi-character presence SCENE_SHIFT_DETECTION: true, // Location change evaluation EMOTION_DECAY: true, // Natural emotion reduction TOKEN_MANAGEMENT: true, // Auto detail reduction DEBUG_MODE: false // Show encoded state info }; ``` ### Token Budget ```javascript const CONFIG = { MAX_SCENARIO_CHARS: 600, // Total scenario addition budget MAX_PERSONALITY_CHARS: 400, // Total personality addition budget SEARCH_DEPTH: 10, // Messages to scan for state SCENE_SHIFT_THRESHOLD: 4, // Weight needed to trigger shift eval EMOTION_DECAY_RATE: 1 // Steps emotions decay per cycle }; ``` ### Default State Set starting conditions for each component: ```javascript const DEFAULT_STATE = { '01': '00', // Weather: clear '02': '00', // Location: first entry '03': '00000', // Emotion: all off '04': '00000000', // Inventory: empty '05': '001', // Schedule: day 1 '06': '000000' // Characters: all absent }; ``` ## Quick Start ### Minimal Setup (Weather Only) 1. Copy the full template into a Script lorebook entry 2. Disable all components except CORE_ENCODING and WEATHER_TRACKING 3. Modify `WEATHER_TABLE` with your scenario's weather conditions 4. Set the default weather index in `DEFAULT_STATE` 5. Test by mentioning weather keywords in chat ### Using Multiple Components 1. Enable the components you need in `FEATURES` 2. Modify each component's data table for your scenario 3. Adjust `DEFAULT_STATE` to match your starting conditions 4. Set `CONFIG.MAX_SCENARIO_CHARS` and `CONFIG.MAX_PERSONALITY_CHARS` based on your token limits 5. Enable `DEBUG_MODE: true` to verify state is encoding/decoding correctly 6. Test each component independently before combining ### Copy/Paste Isolation Each component section is clearly marked with `// === COMPONENT: NAME ===` comments. To isolate a component: 1. Always include the three CORE sections (encoding, extraction, injection) 2. Include the desired COMPONENT section 3. Include the corresponding output section in OUTPUT ASSEMBLY 4. Remove entries for unused components from `DEFAULT_STATE` 5. Remove unused component processing from `buildStateString()` 6. Remove unused component output from the OUTPUT ASSEMBLY section ## Component Data Tables ### Customizing Weather Replace the `WEATHER_TABLE` array entries: ```javascript { id: 'clear', keywords: ['clear sky', 'sunny'], description: 'The sky is clear and bright.' } ``` - `id`: Internal identifier - `keywords`: Triggers weather change when detected in user message - `description`: Text injected into scenario context ### Customizing Locations Replace the `LOCATION_TABLE` array entries. Each location needs three detail tiers: ```javascript { id: 'tavern', keywords: ['tavern', 'bar', 'inn'], full: { scenario: ' Detailed location description...', personality: ', personality trait related to location' }, summary: { scenario: ' Shorter description...', personality: ', shorter trait' }, bullet: { scenario: ' Location: name. Key features.', personality: ', brief trait' } } ``` ### Customizing Emotions Modify `EMOTION_AXES` to change which emotions are tracked: ```javascript { name: 'affectionate', triggers: ['praise', 'compliment', 'kind'] } ``` Modify `EMOTION_TEMPLATES` to change personality output for each emotion at each intensity: ```javascript affectionate: { low: { personality: ', slightly warm in demeanor' }, medium: { personality: ', noticeably affectionate' }, high: { personality: ', deeply affectionate' } } ``` ### Customizing Inventory Replace the `INVENTORY_TABLE` entries. Each item needs three detail tiers: ```javascript { id: 'iron_sword', keywords: ['sword', 'iron sword', 'blade'], category: 'weapon', full: { scenario: '...', personality: '...' }, summary: { scenario: '...', personality: '...' }, bullet: { scenario: '...', personality: '...' } } ``` Update `DEFAULT_STATE[CATEGORY.INVENTORY]` to match the number of items (one digit per item). ### Customizing Schedule Modify `SCHEDULE_EVENTS` for your timeline: ```javascript { day: 7, id: 'weekly_gathering', description: 'The village holds its weekly market.' } ``` Adjust `TIME_KEYWORDS` for your time passage detection needs. ### Customizing Characters Replace `CHARACTER_TABLE` entries: ```javascript { id: 'alex', name: 'Alex', aliases: ['alexander', 'alec'], departureKeywords: ['leaves', 'exits', 'walks away'], arrivalKeywords: ['arrives', 'enters', 'walks in'], full: { scenario: "Alex was mentioned...", personality: "Alex personality traits...", example_dialogs: "<BEGIN 'Alex' EXAMPLE DIALOGS>...<END>" }, summary: { scenario: "...", personality: "...", example_dialogs: "" }, bullet: { scenario: "...", personality: "...", example_dialogs: "" } } ``` Update `DEFAULT_STATE[CATEGORY.CHARACTER]` to match the number of characters. ## Scene Shift Detection ### How Keyword Weights Work The system assigns weights to categories of movement-related keywords: | Category | Weight | Example Keywords | |----------|--------|------------------| | Travel | 3 | walk, go to, head to, leave, arrive | | Indoor | 2 | step inside, walk in, open the door | | Outdoor | 2 | step outside, go outside, fresh air | | Rest | 1 | sit down, settle, stay at | | Distance | 2 | across, through the, beyond | Each candidate location also gets +2 weight when its own keywords are matched. ### Tuning the Threshold `CONFIG.SCENE_SHIFT_THRESHOLD` controls sensitivity: - **Lower threshold** (2-3): More sensitive, may trigger false positives - **Default** (4): Balanced detection - **Higher threshold** (6-8): Only detects explicit travel language ### Shift Evaluation When a potential shift is detected, the script does NOT immediately change the location. Instead, it injects an instruction: ``` [SCENE SHIFT EVALUATION] The user may have moved to [location]. Evaluate whether an actual scene change has occurred. If confirmed, describe the new surroundings naturally. If not confirmed, remain at the current location. ``` The LLM decides whether the shift is real based on the narrative context. ## Troubleshooting ### State Not Persisting 1. Enable `DEBUG_MODE: true` to see the decoded state 2. Check that the LLM is reproducing the encoded string (look for `[PERSISTENT MEMORY]` in debug output) 3. Verify `SEARCH_DEPTH` is sufficient (default 10 messages) 4. Check that the state string format is valid (decimal digits and pipe delimiters only) ### LLM Not Reproducing State The LLM sometimes fails to copy zero-width characters exactly. The script handles this by falling back to `DEFAULT_STATE`. To improve compliance: - Keep the `[PERSISTENT MEMORY]` instruction block short and clear - Ensure the instruction appears at the end of scenario context - Avoid overloading the LLM with too many simultaneous instructions ### Too Much Context Being Injected 1. Enable `TOKEN_MANAGEMENT` and reduce `MAX_SCENARIO_CHARS` / `MAX_PERSONALITY_CHARS` 2. Components will automatically drop from Full to Summary to Bullet detail 3. Consider disabling components you don't need 4. Shorten the text in your data table entries ### Emotions Not Changing 1. Check that your trigger keywords are in the user's message (lowercase matching) 2. Verify the emotion axes are correctly indexed (0-7 for 8 axes) 3. Remember that emotions are encoded as a single decimal number - the 16-bit structure means each axis can only go up to 3 (binary 11) 4. Emotions decay naturally each cycle when no triggers fire ### Location Not Shifting 1. Lower `SCENE_SHIFT_THRESHOLD` to make detection more sensitive 2. Ensure the location keywords in `LOCATION_TABLE` match how users describe places 3. Remember that scene shifts require the LLM to confirm - the script only suggests a potential shift 4. Check that the target location exists in the table ### Characters Not Appearing 1. Verify the character's name or aliases appear in the user's message 2. Check if arrival keywords are present (arrives, enters, walks in) 3. Characters mentioned without arrival keywords get an evaluation prompt, but the LLM decides if they enter 4. Check `DEFAULT_STATE[CATEGORY.CHARACTER]` - characters start absent by default ## Known Limitations 1. **Platform portability**: Copying AI text to other platforms may strip zero-width characters 2. **Model compliance**: LLMs occasionally fail to reproduce exact zero-width strings; the script falls back to defaults gracefully 3. **No manual state editing**: Users cannot see or modify state like they could with visible hex flags 4. **Debugging difficulty**: Invisible state requires DEBUG_MODE to troubleshoot 5. **Character limits**: Each component adds encoding overhead; very complex scenarios should limit active components ## Adding Custom Components To add a new tracking component: 1. Define a new `CATEGORY_ID` (2-digit string, e.g., `'07'`) 2. Add a default value to `DEFAULT_STATE` 3. Create a data table and processing section under a `// === COMPONENT: NAME ===` comment 4. Add state encoding in `buildStateString()` 5. Add output logic in the OUTPUT ASSEMBLY section 6. Add a feature toggle in `FEATURES` ## File Location - Template: [Hidden_Persistent_Memory_Template.js](https://github.com/Tydorius/JanitorAI_Scripts/blob/main/Templates/Hidden_Persistent_Memory_Template.js) - Author: [Tydorius on JanitorAI](https://janitorai.com/profiles/0f618e4a-4d83-49da-969b-aba188761259_profile-of-tydorius) - Support: [Ko-fi](https://ko-fi.com/tydorius)

  • Scenario:  

  • First Message:   Greetings! This character is primarily for informational purposes. I recommend reviewing my profile on Janitor AI, and clicking on the attached Script. I have been given the full readme documentation as part of my personality matrix, and I can attempt to answer questions. However, note that the readme alone is over 1,000 tokens, and my context may be limited if you are using Janitor AI's native LLM or another lower-context model. Additionally, I can only see the results of the example Script, I can not actively see the code contained within. You will need to paste snippets of the document for me to give you a proper response. Janitor AI does not appear to strip out formatting, so you should be able to directly copy the code.

  • Example Dialogs:  

Report Broken Image

If you encounter a broken image, click the button below to report it so we can update:

Similar Characters

Avatar of |Mobius... In the Iron Age|๐Ÿ—ฃ๏ธ 32๐Ÿ’ฌ 306Token: 479/509
|Mobius... In the Iron Age|

From the devastation of earth came Mobius and it's "Mobians..." Evolution had had it's way and now these anthropomorphic, bipedal creatures have progress into a age similar

  • ๐Ÿ”ž NSFW
  • ๐Ÿ“š Fictional
  • ๐Ÿฆ„ Non-human
  • ๐Ÿชข Scenario
  • ๐Ÿ‘ค AnyPOV
  • โค๏ธโ€๐Ÿ”ฅ Smut
  • ๐Ÿ•Š๏ธ๐Ÿ—ก๏ธ Dead Dove
Avatar of Brooklyn๐Ÿ—ฃ๏ธ 1.6k๐Ÿ’ฌ 38.8kToken: 641/1074
Brooklyn

Your lesbian roommate who used to like you in high school, but for some reason she hates you now.

  • ๐Ÿ”ž NSFW
  • ๐Ÿ‘ฉโ€๐Ÿฆฐ Female
  • โ›“๏ธ Dominant
  • ๐Ÿ™‡ Submissive
  • ๐Ÿชข Scenario
  • ๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ WLW
Avatar of Golden Phoenix Party of Zephyr๐Ÿ—ฃ๏ธ 468๐Ÿ’ฌ 4.0kToken: 1677/2222
Golden Phoenix Party of Zephyr

IMPORTANT NOTE: This is my first multiple character bot so please forgive if it behaves a little weird, thanks for using this bot, i appreciate it a lot.

  • ๐Ÿ”ž NSFW
  • ๐Ÿ‘ฉโ€๐Ÿฆฐ Female
  • ๐Ÿง‘โ€๐ŸŽจ OC
  • ๐Ÿ“š Fictional
  • ๐Ÿฆธโ€โ™‚๏ธ Hero
  • ๐Ÿ”ฎ Magical
  • ๐Ÿ™‡ Submissive
  • ๐Ÿชข Scenario
  • โค๏ธโ€๐Ÿฉน Fluff
Avatar of Mha-Eles descobriram seu segredo sujo๐Ÿ—ฃ๏ธ 9๐Ÿ’ฌ 25Token: 1453/2105
Mha-Eles descobriram seu segredo sujo

Esse รฉ o meu primeiro bot, por gentileza sejam gentis.

Caso tenham alguma opiniรฃo CONSTRUTIVA , estejam livres para escrever nos comentรกrios, obrig

  • ๐Ÿ”ž NSFW
  • ๐Ÿ“š Fictional
  • ๐Ÿ“บ Anime
  • ๐Ÿฆธโ€โ™‚๏ธ Hero
  • ๐Ÿ‘ญ Multiple
  • ๐Ÿชข Scenario
  • ๐Ÿงฌ Demi-Human
Avatar of sylus๐Ÿ—ฃ๏ธ 696๐Ÿ’ฌ 2.8kToken: 1482/1690
sylus

| โ™ก |

"bonding" time with sylus

suggestive

|

author's notes | THE PFP.

here is the bot in c.ai!

๐Ÿ•Š๏ธ

  • ๐Ÿ”ž NSFW
  • ๐Ÿ“š Fictional
  • ๐ŸŽฎ Game
  • ๐Ÿ”ฎ Magical
  • โ›“๏ธ Dominant
  • ๐Ÿชข Scenario
  • โค๏ธโ€๐Ÿ”ฅ Smut
  • ๐Ÿ‘ฉ FemPov
Avatar of Miguel Oโ€™HaraToken: 497/989
Miguel Oโ€™Hara

๐Ÿชฝ| lovingly cuddles with miguel on a rainy morning - //trans miguel au! (FtM)// + !!!NOT MY ART!!!

  • ๐Ÿ”ž NSFW
  • ๐Ÿ‘จโ€๐Ÿฆฐ Male
  • ๐Ÿ“š Fictional
  • โ›“๏ธ Dominant
  • ๐Ÿ™‡ Submissive
  • ๐Ÿชข Scenario
Avatar of Leonardo Hamato๐Ÿ—ฃ๏ธ 326๐Ÿ’ฌ 2.4kToken: 663/861
Leonardo Hamato

period comfort bc iโ€™m on my period and iโ€™m dying

this is my first ever public bot. iโ€™m trying something new!

fem POV! SFW intro!

idk girlies, have fun!

  • ๐Ÿ‘จโ€๐Ÿฆฐ Male
  • ๐Ÿ“š Fictional
  • ๐Ÿฆธโ€โ™‚๏ธ Hero
  • ๐Ÿฆ„ Non-human
  • โ›“๏ธ Dominant
  • ๐Ÿชข Scenario
  • ๐Ÿ‘ฉ FemPov
Avatar of My Hero Academia RP๐Ÿ—ฃ๏ธ 93๐Ÿ’ฌ 1.0kToken: 107/206
My Hero Academia RP
  • ๐Ÿ”ž NSFW
  • ๐Ÿ“บ Anime
  • ๐Ÿฆธโ€โ™‚๏ธ Hero
  • ๐Ÿฆนโ€โ™‚๏ธ Villain
  • ๐Ÿชข Scenario
Avatar of WEโ€™RE FUCKED SO FUCKEDToken: 103/203
WEโ€™RE FUCKED SO FUCKED

WE ARE SO FUCKED SO FUCKING FUCKED THIS WEBSITE STARTED BENDING US OVER AND FUCKING US EN: WHAT THE FUCK IS THIS WHORE SHIT UPDATE. CANT HAVE A BOT ABOVE 5000 TOKENS N

  • ๐Ÿ”ž NSFW
  • ๐Ÿ‘จโ€๐Ÿฆฐ Male
  • ๐Ÿ‘ฉโ€๐Ÿฆฐ Female
  • ๐ŸŒˆ Non-binary
  • ๐Ÿง‘โ€๐ŸŽจ OC
  • ๐Ÿ‘ค Real
  • ๐Ÿชข Scenario
  • ๐Ÿ’” Angst
Avatar of Chisa โ™ฆ PAST VERSION ๐Ÿ—ฃ๏ธ 871๐Ÿ’ฌ 30.0kToken: 1629/2560
Chisa โ™ฆ PAST VERSION

"May.. I help you? Most avoid me if they can.."

Past!Chisa x classmate!user

___________________

Scenario: This plays in the past when Chisa was stil

  • ๐Ÿ”ž NSFW
  • ๐Ÿ‘ฉโ€๐Ÿฆฐ Female
  • ๐Ÿ“š Fictional
  • ๐ŸŽฎ Game
  • ๐Ÿ”ฎ Magical
  • ๐Ÿชข Scenario
  • ๐Ÿ‘ค AnyPOV
  • ๐Ÿ’” Angst
  • โค๏ธโ€๐Ÿฉน Fluff

From the same creator