Configuration Options for moeru‑ai/airi: A Complete Guide to the Defu‑Based Config System
The moeru‑ai/airi repository uses a hierarchical, defu‑based configuration system that merges default TypeScript objects, environment variables, JSON files, and runtime updates through a singleton ConfigManager.
Understanding the configuration options for moeru‑ai/airi is essential for customizing the Twitter automation and AI agent behaviors. The project implements a unified configuration layer in services/twitter-services/src/config/ that supports deep merging via defu, allowing granular overrides without breaking the default schema.
How the Configuration System Works
The configuration hierarchy follows a strict precedence order: hard‑coded defaults → environment variables → JSON file → runtime updates. All values flow through the ConfigManager singleton exposed by useConfigManager().
In services/twitter-services/src/config/index.ts, the manager initializes by calling getDefaultConfig() from services/twitter-services/src/config/types.ts, then conditionally loads a JSON file specified by the CONFIG_PATH environment variable (defaulting to ./twitter-config.json). The merge uses defu from @moeru/std, ensuring that partial objects only override specific keys rather than replacing entire sections.
Configuration Options Reference
The top‑level Config interface defined in services/twitter-services/src/config/types.ts organizes options into logical groups.
Browser Configuration (BrowserConfig)
Controls Puppeteer/Playwright behavior via Stagehand and BrowserBase:
browser: {
apiKey: string, // BROWSERBASE_API_KEY
endpoint?: string, // Optional Stagehand endpoint
headless: boolean, // BROWSER_HEADLESS
userAgent: string, // BROWSER_USER_AGENT
viewport: { width: number, height: number }, // BROWSER_VIEWPORT_*
timeout: number, // BROWSER_TIMEOUT
requestTimeout: number, // BROWSER_REQUEST_TIMEOUT
requestRetries: number // BROWSER_REQUEST_RETRIES
}
Twitter API Credentials
Optional OAuth 1.0a credentials for API v1.1 or v2 endpoints:
credentials?: {
apiKey?: string, // TWITTER_API_KEY
apiSecret?: string, // TWITTER_API_SECRET
accessToken?: string, // TWITTER_ACCESS_TOKEN
accessTokenSecret?: string // TWITTER_ACCESS_TOKEN_SECRET
}
Twitter Request Options
Default parameters for timeline and search operations:
twitter: {
defaultOptions?: {
timeline?: { count: number, includeReplies: boolean, includeRetweets: boolean }
search?: SearchOptions
}
}
Adapter Settings (Airi and MCP)
Toggles for external service integration:
adapters: {
airi?: {
url?: string, // AIRI_URL (default: http://localhost:3000)
token?: string, // AIRI_TOKEN
enabled: boolean // ENABLE_AIRI
}
mcp?: {
port?: number, // MCP_PORT (default: 8080)
enabled: boolean // ENABLE_MCP
}
}
System-Wide Settings
Global runtime behavior:
system: {
logLevel: 'error' | 'warn' | 'info' | 'verbose' | 'debug'
logFormat?: 'json' | 'pretty'
concurrency: number // CONCURRENCY (default: 1)
}
Loading and Merging Configuration Files
The ConfigManager constructor in services/twitter-services/src/config/index.ts handles file loading:
const configPath = process.env.CONFIG_PATH || path.join(process.cwd(), 'twitter-config.json')
configInstance = new ConfigManager(fs.existsSync(configPath) ? configPath : undefined)
If the file exists, ConfigManager.loadFromFile() reads the JSON and applies defu to merge it with the defaults. Errors during parsing are caught and logged via logger.config.errorWithError.
Runtime Configuration Updates
You can modify configuration without restarting the process using updateConfig():
import { useConfigManager } from '@/services/twitter-services/src/config'
function onUserChanges(newOpts: Partial<Config>) {
useConfigManager().updateConfig(newOpts)
}
This method uses defu to deep‑merge the new partial object onto the existing configuration, ensuring that only specified keys change while preserving the rest of the state.
Environment Variable Mapping
The getDefaultConfig() function in services/twitter-services/src/config/types.ts maps specific environment variables to configuration keys:
| Environment Variable | Config Path | Default Value |
|---|---|---|
BROWSERBASE_API_KEY |
browser.apiKey |
'' |
BROWSER_HEADLESS |
browser.headless |
false |
BROWSER_USER_AGENT |
browser.userAgent |
Mozilla/5.0... |
BROWSER_VIEWPORT_WIDTH |
browser.viewport.width |
1280 |
BROWSER_TIMEOUT |
browser.timeout |
30000 |
BROWSER_REQUEST_TIMEOUT |
browser.requestTimeout |
20000 |
BROWSER_REQUEST_RETRIES |
browser.requestRetries |
2 |
TWITTER_API_KEY |
credentials.apiKey |
undefined |
TWITTER_API_SECRET |
credentials.apiSecret |
undefined |
TWITTER_ACCESS_TOKEN |
credentials.accessToken |
undefined |
TWITTER_ACCESS_TOKEN_SECRET |
credentials.accessTokenSecret |
undefined |
AIRI_URL |
adapters.airi.url |
http://localhost:3000 |
AIRI_TOKEN |
adapters.airi.token |
'' |
ENABLE_AIRI |
adapters.airi.enabled |
false |
MCP_PORT |
adapters.mcp.port |
8080 |
ENABLE_MCP |
adapters.mcp.enabled |
true |
CONCURRENCY |
system.concurrency |
1 |
CONFIG_PATH |
N/A (loader path) | ./twitter-config.json |
Additionally, the server‑runtime package provides optionOrEnv() in packages/server-runtime/src/config/config.ts for CLI tools that need to fall back to environment variables when explicit options are not provided.
Accessing Configuration in Code
Always use the useConfigManager() singleton rather than importing raw JSON:
import { useConfigManager } from '@/services/twitter-services/src/config'
// Read current configuration
const cfg = useConfigManager().getConfig()
// Access nested values safely
console.log('Browser endpoint →', cfg.browser.endpoint)
console.log('Enabled adapters →',
Object.entries(cfg.adapters)
.filter(([, v]) => v?.enabled)
.map(([k]) => k)
)
This ensures you receive the fully resolved configuration that includes all merges from defaults, environment variables, and runtime updates.
Summary
- Hierarchical merging – Configuration options for moeru‑ai/airi are resolved through a four‑layer hierarchy: hard‑coded defaults → environment variables → JSON file → runtime updates.
- Deep merge via defu – The
ConfigManagerusesdefufrom@moeru/stdto perform deep merges, ensuring partial objects only override specific keys. - Singleton access – Always retrieve settings through
useConfigManager()inservices/twitter-services/src/config/index.tsto guarantee a single source of truth. - Environment mapping – Dozens of environment variables (prefixed with
BROWSER_,TWITTER_,AIRI_,MCP_, etc.) map directly to nested configuration keys. - Runtime mutability – Call
updateConfig()to modify settings without restarting the process, enabling dynamic UI‑driven configuration changes.
Frequently Asked Questions
What is the default configuration file path for airi?
By default, the ConfigManager looks for twitter-config.json in the current working directory. You can override this by setting the CONFIG_PATH environment variable to point to any JSON file location.
How does airi handle configuration conflicts between environment variables and JSON files?
The system uses a precedence stack: environment variables are baked into the default configuration object first, then the JSON file (if present) is deep‑merged on top using defu. This means JSON file values override environment defaults, and runtime updates override both.
Can I update airi configuration options at runtime without restarting?
Yes. The ConfigManager exposes updateConfig(partialConfig) which performs a live deep‑merge into the existing configuration singleton. This is used by UI panels and plugins to toggle adapters or adjust browser settings on the fly.
Where is the ConfigManager singleton defined in the moeru-ai/airi repository?
The singleton is defined and exported from services/twitter-services/src/config/index.ts. It instantiates the ConfigManager class, which loads the initial state from getDefaultConfig() (located in services/twitter-services/src/config/types.ts) and optionally merges a JSON configuration file.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →