ctx0-system-entries.md

ctx0 System Entries

This document describes the system entries feature - global default vault entries that all users inherit, defined in code as the single source of truth.


Overview

System entries are global defaults that exist in code, not in the database. They provide:

  • Instant updates to all users - Change code, redeploy, everyone sees it immediately
  • No migration needed - Existing users see system entries without database seeding
  • User customization - Users can "fork" entries by editing them
  • Reset to default - Users can revert customizations anytime
┌─────────────────────────────────────────────────────────────────┐
│                    GLOBAL SYSTEM ENTRIES                         │
│                   (defined in code - you control)                │
│                                                                   │
│  packages/ctx0/src/system-entries/                               │
│  ├── index.ts              # Exports SYSTEM_ENTRIES array        │
│  ├── types.ts              # SystemEntry, MergedEntry types      │
│  ├── folders.ts            # /skills/, /agents/ folders          │
│  └── agents/                                                     │
│      ├── ctx0.ts           # ctx0 AGENT.md + config.json         │
│      └── curator.ts        # curator AGENT.md + config.json      │
│                                                                   │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             │ merged at read time
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│                    USER ENTRIES (overrides)                      │
│                   (ctx0_entries table)                           │
│                                                                   │
│  Only contains entries the user has customized:                  │
│  - User edits /agents/curator/AGENT.md → fork saved here         │
│  - User creates /agents/my-agent/ → stored here                  │
│  - User deletes fork → reverts to system default                 │
│                                                                   │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│                    MERGED VAULT VIEW                             │
│                                                                   │
│  /skills/                  ← system (locked folder)              │
│  /agents/                  ← system (locked folder)              │
│  /agents/ctx0/AGENT.md     ← system OR user fork                 │
│  /agents/curator/AGENT.md  ← system OR user fork                 │
│  /agents/my-agent/         ← user-created                        │
│  /contacts/sarah-chen      ← user-created                        │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

User Flow

  1. View vault → User sees merged view (system + their entries)
  2. Edit system entry → Fork created in their table, marked is_fork=true
  3. See customized badge → UI shows "CUSTOM" badge on forked entries
  4. Reset to default → Delete fork from their table, system version shows again
  5. Owner updates → You change code, all non-forked users see update instantly

Current System Entries

Folders (Locked)

PathTypeDescription
/skillsfolderSkills folder (locked)
/agentsfolderAgents folder (locked)
/agents/ctx0folderctx0 agent folder (locked)
/agents/curatorfolderCurator agent folder (locked)

Files (Editable / Forkable)

PathTypeDescription
/agents/ctx0/AGENT.mdagentctx0 system prompt
/agents/ctx0/config.jsonagentctx0 configuration
/agents/curator/AGENT.mdagentCurator system prompt
/agents/curator/config.jsonagentCurator configuration

Code Structure

SystemEntry Type

typescript
interface SystemEntry { /** Full path (e.g., "/agents/ctx0/AGENT.md") */ path: string; /** Entry kind (file or folder) */ entryKind: 'file' | 'folder'; /** Entry type */ entryType: EntryType; /** Whether the entry is locked (cannot be edited/deleted) */ isLocked: boolean; /** Entry title */ title?: string; /** Content (for files) */ content?: string; /** Version number - increment when you update content */ version: number; }

Source Files

FilePurpose
packages/ctx0/src/system-entries/index.tsMain export, SYSTEM_ENTRIES array
packages/ctx0/src/system-entries/types.tsTypeScript interfaces
packages/ctx0/src/system-entries/folders.tsSystem folder definitions
packages/ctx0/src/system-entries/agents/ctx0.tsctx0 agent content
packages/ctx0/src/system-entries/agents/curator.tsCurator agent content

Helper Functions

typescript
import { SYSTEM_ENTRIES, getSystemEntry, isSystemPath, getSystemEntriesUnderPath, getSystemChildren, } from '@bot0/ctx0'; // Get a system entry by path const entry = getSystemEntry('/agents/ctx0/AGENT.md'); // Check if a path is a system path const isSystem = isSystemPath('/agents/ctx0'); // Get all entries under a path const children = getSystemEntriesUnderPath('/agents');

Vault Merge Logic

The vault module provides functions to merge system entries with user entries:

typescript
import { getMergedVaultTree, getMergedEntryContent, getMergedEntry, } from '@bot0/ctx0'; // Get the full merged tree for a user const tree = await getMergedVaultTree(supabase, userId); // Get content for a path (checks user first, then system) const content = await getMergedEntryContent(supabase, userId, '/agents/ctx0/AGENT.md'); // Get a single merged entry const entry = await getMergedEntry(supabase, userId, '/agents/ctx0/AGENT.md');

MergedEntry Type

typescript
interface MergedEntry { path: string; entryKind: 'file' | 'folder'; entryType: EntryType; isLocked: boolean; title?: string; version: number; /** True if this is from system entries */ isSystem: boolean; /** True if user has forked this system entry */ isFork: boolean; /** True if user can reset to system default */ canReset: boolean; }

Fork and Reset Logic

Forking a System Entry

When a user edits a system entry, create a fork:

typescript
import { forkSystemEntry } from '@bot0/ctx0'; // User edits /agents/ctx0/AGENT.md await forkSystemEntry( supabase, userId, '/agents/ctx0/AGENT.md', newContent );

This creates a row in ctx0_entries with is_fork=true.

Resetting to Default

When a user wants to revert to the system version:

typescript
import { resetToSystemDefault } from '@bot0/ctx0'; // Delete the user's fork await resetToSystemDefault( supabase, userId, '/agents/ctx0/AGENT.md' );

This deletes the user's fork, so they see the system version again.


Desktop UI

The Desktop app shows system entries with visual indicators:

IconMeaning
Folder (yellow)Regular folder
Folder (gray) with lockLocked system folder
MD iconMarkdown file
{} icon (yellow)JSON file

Badges

BadgeMeaning
SYS (purple)System entry - defined by bot0
CUSTOM (green)User has customized this system entry

Status Bar

When viewing a system entry, the content area shows:

  • "System entry" indicator for unmodified system entries
  • "Customized" indicator for forked entries
  • "Reset to default" button for forked entries

Adding New System Entries

1. Add to Source

Create or update files in packages/ctx0/src/system-entries/:

typescript
// packages/ctx0/src/system-entries/agents/my-agent.ts import type { SystemEntry } from '../types'; export const MY_AGENT_MD = `--- name: my-agent description: My custom agent tools: - ctx0_remember --- You are my-agent... `; export const MY_AGENT: SystemEntry[] = [ { path: '/agents/my-agent/AGENT.md', entryKind: 'file', entryType: 'agent', isLocked: false, title: 'My Agent', content: MY_AGENT_MD, version: 1, }, ];

2. Add to SYSTEM_ENTRIES

Update packages/ctx0/src/system-entries/index.ts:

typescript
import { MY_AGENT } from './agents/my-agent'; export const SYSTEM_ENTRIES: SystemEntry[] = [ ...SYSTEM_FOLDERS, ...CTX0_AGENT, ...CURATOR_AGENT, ...MY_AGENT, // Add new entries ];

3. Rebuild and Deploy

bash
pnpm --filter @bot0/ctx0 build

All users will see the new entry immediately (unless they've forked it).


Updating System Entry Content

To update a system entry's content:

  1. Edit the content in the source file
  2. Increment the version field
  3. Rebuild and deploy
typescript
// Before export const CTX0_AGENT: SystemEntry[] = [ { path: '/agents/ctx0/AGENT.md', content: CTX0_AGENT_MD, version: 1, // Current version }, ]; // After updating content export const CTX0_AGENT: SystemEntry[] = [ { path: '/agents/ctx0/AGENT.md', content: CTX0_AGENT_MD_V2, version: 2, // Increment version }, ];

The version field can be used to show "update available" indicators for users who have forked old versions.


Database Schema

The ctx0_entries table has these columns for system entry support:

ColumnTypeDescription
is_systembooleanEntry was created by system (legacy)
is_lockedbooleanEntry cannot be modified/deleted
is_forkbooleanUser fork of a system entry

Benefits

  1. Code as source of truth - System entries live in git, version controlled
  2. No database seeding - No migration jobs, no seed scripts
  3. Instant updates - Change code, redeploy, everyone sees it
  4. Clean separation - User table only has their customizations
  5. Reset capability - Users can always get back to defaults