LengoAI

Memory

What LengoAI has learned: outcomes of past goals, incidents, runbooks, conventions, decision records and support-ticket themes. Personal data is redacted before anything is stored.

CONV-feature-flags#3 · Feature flag conventions > Guarding a change conventions
Read the flag once per request with the user ID as context: `flags.is_enabled(FLAG_KEY, user_id)`. Keep the old behaviour as the flag-off path, unchanged. The new behaviour lives only in the flag-on path. Never read a flag inside a loop or a retry, because the answer could change mid-request. In PesaLite, a goal's change is wired in `apps/pesalite/app/release.py`: `FLAG_KEY` (the planned key, exactly), `TREATMENT_RETRY_POLICY` (what the flag turns on, one of the policies in `app/retry.py`), and `in_treatment`, which returns `flags.is_enabled("<flag key>", user_id)` with the key written out. P
ADR-001#1 · ADR-001: Release behind feature flags, not by redeploying conventions
> Synthetic architecture decision record for LengoAI.
ADR-001#2 · ADR-001: Release behind feature flags, not by redeploying > Status conventions
Accepted.
ADR-001#3 · ADR-001: Release behind feature flags, not by redeploying > Context conventions
A release that hurts users must be reversed in seconds. Rolling back a deployment takes minutes: build, push, deploy and warm-up. It also reverses every other change in that deployment. We also need to compare users with and without a change at the same moment, which a deployment can't do.
ADR-001#4 · ADR-001: Release behind feature flags, not by redeploying > Decision conventions
Every user-facing change ships dark, behind a feature flag that is off by default. Deployment and release are separate steps. Lengo Core releases by changing the flag's percentage through the GitLab Feature Flags API, and kills by deactivating the flag. Clients refresh flag state every 5 seconds.
ADR-001#5 · ADR-001: Release behind feature flags, not by redeploying > Consequences conventions
A kill is one API call plus one client refresh, so the change is undone for users within seconds, without a redeploy. Flag-on and flag-off users form concurrent cohorts, which is what the statistics engine compares. The cost is code that carries both paths until the Scribe's cleanup merge request removes the old one, and a per-project limit on the number of flags.
ADR-002#1 · ADR-002: Decisions with consequences are made in code, not by a model conventions
> Synthetic architecture decision record for LengoAI.
ADR-002#2 · ADR-002: Decisions with consequences are made in code, not by a model > Status conventions
Accepted.
ADR-002#3 · ADR-002: Decisions with consequences are made in code, not by a model > Context conventions
LengoAI's agents are language models. They plan, write code and explain well, but they can be wrong in confident ways, they vary between runs, and they can't be held to an error rate. Expanding a rollout, killing a flag, merging, closing a goal or writing memory changes what users experience or what the system believes. Those decisions need to be reproducible and auditable.
ADR-002#4 · ADR-002: Decisions with consequences are made in code, not by a model > Decision conventions
LLMs propose, code disposes. Agents produce plans, code and explanations, and they hand off through a JSON block that Core validates. Lengo Core makes every decision that has consequences, using deterministic, tested code: the policy engine (`check_policy`), the statistics engine (`decide`), the flag controller and the state machine. The Analyst explains a decision but can't change it.
ADR-002#5 · ADR-002: Decisions with consequences are made in code, not by a model > Consequences conventions
The same data always gives the same decision, and every decision is written to the audit log with the numbers behind it. Statistical guarantees (false-alarm rates) are measured by simulation, not hoped for. Agents can still be wrong, but only in places a human or a check can catch: a merge request that fails the pipeline, a plan that fails validation, or a citation that wasn't supplied.
AGENTS#1 · AGENTS.md: conventions for every agent working in this repository conventions
GitLab Duo reads this file automatically, and Lengo indexes it into memory as a convention (`AGENTS.md#<section>`). Humans follow the same rules.
AGENTS#2 · AGENTS.md: conventions for every agent working in this repository > 1. Who decides what conventions
**LLMs propose, code disposes.** Agents plan, write code and explain. Lengo Core makes every decision that has consequences: accepting a handoff, merging, changing or killing a feature flag, calling a goal `proven`, closing or reopening a goal, and writing memory. Never try to do any of these yourself, and never claim they happened unless Core's note says so.
AGENTS#3 · AGENTS.md: conventions for every agent working in this repository > 2. Repository map conventions
| Path | What lives there | May agents edit it? | |---|---|---| | `apps/pesalite/app/` | The demo payments app that Lengo releases | **Yes**: this is where goal changes go | | `apps/pesalite/tests/` | PesaLite tests | **Yes**: every change adds or updates tests here | | `apps/pesalite/app/db.py` | Balance ledger storage | **No** (protected) | | `core/` | Lengo Core itself | **No** (protected: Core enforces the rules, so a change to it goes through an owner) | | `memory/` | Seed knowledge for RAG | Scribe only, through an MR | | `.gitlab/duo/` | Agent flows and prompts | No | | `infra/**`, `.gi
AGENTS#4 · AGENTS.md: conventions for every agent working in this repository > 3. Rules for every code change conventions
1. **Behind a feature flag.** New behaviour is off unless the flag is on. Read flags with `app.flags.is_enabled("<flag_key>", user_id)`. The flag key is `goal_<goal number>_<short_name>`, for example `goal_0007_gateway_retry`. The old code path must keep working when the flag is off. See `memory/conventions/feature-flags.md`. 2. **Tests required.** Every MR adds or updates tests that cover both flag states. 3. **Small changes.** At most `code.max_files_changed` files and `code.max_lines_changed` changed lines (see `lengo.yml`). Split anything larger. 4. **No secrets, no real data.** Never comm
AGENTS#5 · AGENTS.md: conventions for every agent working in this repository > 4. Branches, commits and MRs conventions
- Branch: `lengo/<goal-id>-<short-slug>` (e.g. `lengo/G-0007-gateway-retry`). - Commits: imperative mood, a reference to the goal (`Refs G-0007`), and DCO sign-off (`Signed-off-by:`). - MR: use the `lengo` MR template. Link the goal issue, name the flag key, list files and tests, state the risk class. - Never merge your own MR. Core merges when policy allows.
AGENTS#6 · AGENTS.md: conventions for every agent working in this repository > 5. The handoff conventions
Every Lengo flow ends by posting **one** note on the goal issue that contains a fenced block tagged `lengo-handoff` with JSON matching `core/lengo_core/schemas/handoff.v1.json`. After posting it, you are done: stop, and don't post anything else. Core validates the block and starts the next step. A malformed block is retried with the error message, up to two times.
AGENTS#7 · AGENTS.md: conventions for every agent working in this repository > 6. IDs conventions
Goals `G-0007` · memory records `M-0031` · runbook steps `RB-004#2` · incidents `INC-0003` · decision records `ADR-002` · ticket clusters `TC-0004`.
CONV-coding#1 · Coding conventions conventions
> Synthetic conventions for the PesaLite demo, written for LengoAI's agents and its human reviewers.
CONV-coding#2 · Coding conventions > Language and style conventions
Python 3.12 with type hints everywhere. Code must pass `ruff check`, `ruff format --check` and `mypy --strict`. Use small functions with one job each. Docstrings explain why a function exists and what it guarantees, not only what it does.
CONV-coding#3 · Coding conventions > Errors and retries conventions
Never swallow exceptions with a bare `except`. Catch the specific errors you expect and let everything else surface. Every call to another service has a timeout. Retries use exponential back-off with jitter and are limited in number. A retry of a payment always reuses the same idempotency key, so the gateway can recognise the repeat.
CONV-coding#4 · Coding conventions > Tests conventions
Every change adds or updates tests in `apps/pesalite/tests/`. A flag-guarded change is tested in both flag states: the old path with the flag off and the new path with the flag on. Tests use the seeded gateway simulator (`GatewaySimulator(seed=...)`), so results are deterministic.
CONV-coding#5 · Coding conventions > Money and data conventions
Amounts are integer cents, never floats. The ledger (`apps/pesalite/app/db.py`) is a protected path: agents must not edit it. All demo data is synthetic. Never log or commit real names, phone numbers, emails or card numbers.
CONV-coding#6 · Coding conventions > Size of a change conventions
Keep merge requests small: at most 8 files and 400 changed lines (`code` in `lengo.yml`). The `policy-check` pipeline job enforces this. Split anything larger into separate goals.
CONV-feature-flags#1 · Feature flag conventions conventions
> Synthetic conventions for the PesaLite demo.
CONV-feature-flags#2 · Feature flag conventions > Naming conventions
Flag keys are `goal_<number>_<short_name>` in lower case, for example `goal_0001_gateway_retry`. Keys start with a letter, use only letters, digits and underscores, and never end with an underscore (GitLab's naming rule).
CONV-feature-flags#4 · Feature flag conventions > Rollout conventions
Lengo Core creates the flag with a "percent of users" strategy (`gradualRolloutUserId`). The group ID is fixed to the flag key, so a user who has the change at 1% keeps it at 10%, 50% and 100%. Steps only increase (1 → 10 → 50 → 100). Each step waits at least `rollout.min_dwell_minutes`, and the statistics engine must say `expand`. The step to 100% also needs the goal to be proven.
CONV-feature-flags#5 · Feature flag conventions > Killing and cleaning up conventions
Only Lengo Core changes or kills flags; agents never call the Feature Flags API. After a goal closes, the Scribe opens a cleanup merge request that removes the flag check and the dead code path, because stale flags make the code harder to reason about. GitLab.com allows 50 to 200 flags per project, depending on the tier.