Lisa is a small remote configuration and feature flag service inspired by systems like Firebase Remote Config.
It allows applications to dynamically change behavior at runtime without redeploying code, while maintaining strict boundaries between public read access and privileged write access.
curl -X POST https://lisa-aopa.onrender.com/create/<project_name>[!NOTE] Response (shown once):
{
"client_api": "public-client-key",
"config_api": "private-config-key"
}-
Mona CLI on PyPI
The command-line tool i created to sync local configuration with the Lisa backend — available on PyPI:
https://pypi.org/project/mona-cli/ -
Example Application Repository
An example of Lisa with Python app using Mona and a Vite + React frontend: https://github.com/haibaaa/lisa-demo.git
Modern applications often need to change behavior after deployment:
- enable or disable features
- adjust UI themes
- tune limits or thresholds
Hard-coding these values couples configuration to releases, increasing risk and slowing iteration.
Lisa solves this by providing a centralized, read-only configuration API for applications, and a protected write interface for operators.
Lisa is composed of three parts:
-
Backend API (Flask)
- Public read-only endpoints for applications
- Private write endpoints for configuration updates
- Enforces trust boundaries structurally
-
CLI (Mona)
- Used by developers/operators to sync local configuration
- Interacts only with privileged endpoints
-
Client Applications
- Consume configuration via simple JSON over HTTP
Mona (CLI) ──▶ Lisa (Flask + DB)
▲
│ JSON over HTTP
│
Client App
Lisa enforces two distinct trust levels:
- endpoint:
get /client/projects/<client_api> - accessible with a public identifier
- read-only by construction
- safe to embed in client applications
- endpoint:
post /sync/<config_api> - requires a secret configuration api key
- used only by operators and the cli
- allows mutation of configuration state
Public keys identify projects.
Private keys authorize mutation.
POST /create/<project_name>
Creates a new project and returns:
client_api— public read keyconfig_api— private write key
Keys are shown only once and must be stored safely.
GET /client/projects/<client_api>
Returns a resolved key–value map:
{
"feature_x_enabled": true,
"theme": "dark"
}POST /sync/<config_api>
Accepts a JSON blob and synchronizes it with the project’s stored configuration.
- Owns API keys
- Acts as a namespace for configuration
- Key–value configuration entries
- Typed values (bool, string, number)
- Always associated with a project
No configuration exists without a project. This invariant is enforced at the database level.
Lisa resolves configuration server-side and returns only the final values to clients.
Clients never receive:
- rules
- metadata
- write capabilities
Lisa does not support a complete client SDK like other mature services yet so users need adapt a thin wrapper around the api for now
Example (React):
fetch(".../client/projects/<client_api>")
.then(res => res.json())
.then(config => {
if (config.feature_x_enabled) enableFeature()
})The demo React app polls the API periodically to detect configuration changes without requiring a page refresh.
- Invalid keys return clear HTTP errors
- Public endpoints cannot mutate state
- Sync operations overwrite atomically
- Errors are logged at the API boundary
The system favors explicit failure over silent misconfiguration.
AI tools were used to:
- accelerate boilerplate generation
- validate architectural ideas
- refine explanations and documentation
AI was not used to:
- design trust boundaries
- make security decisions
- introduce new abstractions without review
All AI-generated code was manually reviewed and adapted to preserve system invariants.
- configuration versioning
- percentage-based rollouts
- conditional targeting
- audit logs
The current structure allows these to be added without breaking existing clients.