English source · 7 min
Changes to Veyndo
Prefer the codebase-memory MCP graph for structural code discovery. Keep Rust modules small and give every source file a responsibility comment; the existing structure check is mandatory.
Understand the existing architecture before extending it
Read the source map for module ownership and Rust services and language boundaries for the actual service, queue and migration contracts. Follow the existing call path from the frontend/API/MCP/flow entry point to its production consumer before changing it. These documents describe one connected system, not alternative implementations.
| Existing owner | Responsibility / entry points |
|---|---|
| Rust commerce binary | src/main.rs is process entry only; domain modules own commerce operations. Store/Admin APIs, MCP and implemented UCP routes reuse those operations, permissions and tenant checks. |
| Rust connector binary | src/bin/connectors.rs and extensions/services/connectors/src/ own shared hosting; provider implementation belongs to the respective extensions/apps/<app>/ package. This is a separate service reached through the permission-aware app gateway, not provider code embedded in checkout. |
| Frontend | frontend/src/ contains modular Studio/storefront clients of the existing APIs. Keep provider credentials and privileged gateway tokens server-side. |
| Durable state and events | PostgreSQL owns commerce state, connector configuration and queues. Commerce outbox/Flow Builder events reach the connector through the existing app action/event contract. Qdrant supplies knowledge vector retrieval, not a second commerce ledger. |
| External extensions | The language-neutral app gateway and documented extension contracts support independent services. Private Payments and Storyfront/Experience implementations stay in their separate repositories. |
Do not create a parallel mailer, queue, settings store, pricing engine, provider registry, MCP command implementation or commerce API to avoid understanding an existing module. Extend its owner and shared contract. For example, order email delivery follows Rust checkout → PostgreSQL outbox → Flow Builder → app gateway → Rust connector → PostgreSQL delivery queue → provider. Preserve its tenant identity, permissions, idempotency, quotas, lease fences and uncertainty handling; do not add direct SMTP calls to checkout or a Python fallback worker.
Money/currency resolution already belongs to src/currencies/ and the shared
commerce calculation path; API/MCP/UI consumers must not implement their own FX
calculator. See multi-currency commerce. A protocol adapter
translates inputs/outputs; it does not become a second owner of business rules.
Product editing preserves aggregate revision for legacy/absolute-stock CAS and
uses contentRevision only when commerce.stock is omitted. Never infer that an
echoed old quantity is a new inventory instruction. The editor omits untouched
stock and adopts the returned current quantity/clocks. Migration 098 observes
existing revisioned writers during rolling releases. Keep both clocks and stock
out of sandbox configuration digests; history restoration never restores stock.
See docs/product-management.md#editing-while-orders-arrive and retain the actual
two-replica purchase/cancellation/MCP regression in production_foundations.
Internationalization contract (mandatory for every new module)
- Every customer/merchant-facing field (including shipping/payment names and descriptions, tax labels, country/region names, product names, SEO, rich descriptions and category content) must accept enabled shop content languages. Do not hard-code four product languages.
- Content editors must use
shared/i18n/ContentLanguage,ContentLanguagePickerandLocalizedField(orshared/geography/TranslationFieldsfor object maps). One selected content language applies to the entire editor, including nested flow nodes. Do not render separate text inputs/areas for every language. The localization gate rejects stacked language value fields; keep its negative controls passing. - Use the shop's
mainLocaleas the per-field fallback.null/missing means inherit; an explicitly empty description must remain empty. Never save inherited values as fabricated translations or silently copy names into every language. - All new interface text and bundled content ships in English, German and Spanish;
preserve French where supported. Use typed shared vocabulary modules, never raw JSX
text/labels.
npm run localizationis required in CI. No legacy literal baseline or record-legacy bypass is allowed. Conditional/fallback/template copy, local string bindings and display props also belong in vocabularies. The explicitlocalization-tokens.jsonlist is only for proper names, protocol identifiers, units and artwork lettering; never add interface prose to silence a failure. - Preserve every
{parameter}in all translations. Usenpm run translationsto export/import existing typed catalogues; imports validate all keys/locales before writing string literals. See the translation guide. - External app hosts pass interface/content/main locales and enabled languages.
Guest apps use
sdk.uiTextfor controls andsdk.textfor merchant content; native and product-slot apps use the same main-language fallback. Do not slice a locale and hard-code English as a content fallback. Verify a non-English-main shop and a fifth content language; arbitrary third-party UI needs its own checks. - Reuse
shared/geographysearch/group pickers for country or region selection. Country checkbox walls and unvalidated free-text subdivision IDs are prohibited. - Newly enabled delivery countries require explicit tax configuration and valid shipping and consumer payment coverage. Do not invent tax law or automatically set new countries to a zero tax rate. Destination conditions run through the existing native Rule Builder.
- Translation/model output is untrusted. Preserve URLs, IDs, units, media and document structure; validate content, tenant permissions and expected revisions on apply. Bulk operations must persist progress and process bounded batches. Test inheritance, a non-English main language, tenant isolation, stale versions and provider failures.
First-party service language boundary
Bundled production commerce and standard provider services run in Rust. Python remains for development tools, tests, documentation, the explicit one-time legacy-data migration and independent example apps. Its presence in the repository does not make it a supported first-party production runtime.
| Python location / purpose | Allowed boundary |
|---|---|
| Verification, differential tests, source/coverage checks and site generation | Development/CI tools only; never required to serve a commerce request or deliver a notification. |
scripts/connectors.py |
Local lifecycle tooling that launches the compiled Rust connector; it is not the email/provider implementation. |
scripts/migrate_connector_state.py |
Explicit offline reader for the old SQLite/Fernet data. Stop the old worker and preserve its backup/key first; pipe records to Rust connectors --import-legacy, which validates and atomically re-encrypts/imports into PostgreSQL. Never import automatically during normal startup. |
scripts/mcp_stdio.py |
Optional client-side JSON-RPC bridge. The hosted /mcp server and its commerce operations run in Rust; no hosted Python MCP backend. |
reference/connectors-python/ |
Archived comparison implementation for differential fixtures and migration understanding. Do not resurrect, import into serving code or package it as a production service. |
| Independent Product Lab / service-example / third-party apps | Deliberately language-independent extension examples, reached through extension contracts. They must not become a required dependency of the core or bundled standard services. |
The final runtime stages of deploy/Dockerfile (commerce) and
extensions/services/connectors/Dockerfile (standard services) contain no Python
interpreter. Keep this boundary when changing images or startup commands: no
Python installation, .py entry point, runtime Python subprocess, archived worker
or fallback provider implementation in either production image. Build/CI tools
and optional independent app images are separate scopes.
The former email_config.py, email_templates.py, email_service.py and
email_delivery.py are reference code, not current service owners. Configuration,
templates and delivery belong to extensions/apps/email/src/; shared actions and queues belong to extensions/services/connectors/src/; use the
module table in the Rust service guide to find each owner.
Do not introduce SQLite, a filesystem spool or process-local authoritative queues
beside the PostgreSQL connector queue. Preserve forced tenant RLS, the dedicated
non-owner production role, encrypted credentials, bounded worker admission and
explicit handling of uncertain external sends.
For a runtime extension or port:
- Identify the existing module, API/app contract, event producer and actual consumer.
- Extend the Rust owner while keeping API, MCP, flow and frontend contracts aligned. External apps can keep their own language; do not pull them into the public core.
- For persisted legacy data, document the explicit backup, stop, import and cutover path. Never run old and new dispatchers simultaneously against the same workload.
- Verify the real path with isolated PostgreSQL tenants and local provider fixtures.
Use the registered
rust_connectors/email_testssuites when changing these services; preserve the original comparison fixtures, concurrency and migration checks. - Update module ownership and service documentation. Check the final runtime image and startup path, not merely whether Rust code exists or unit tests pass.
Scoped ownership rules
Read the matching directory AGENTS.md before changing its owner; cross-directory
work must read every affected owner. Backend work follows src/AGENTS.md, frontend
work follows frontend/AGENTS.md, app/service work follows extensions/AGENTS.md.
Nested rules refine ownership; they never relax root security or runtime contracts.
For changes spanning API, models and UI, trace the shared production consumer first.
| Owner | Additional instructions |
|---|---|
src/cognition/ |
src/cognition/AGENTS.md |
src/ |
src/AGENTS.md |
src/apps/ |
src/apps/AGENTS.md |
extensions/ |
extensions/AGENTS.md |
src/b2b/ |
src/b2b/AGENTS.md |
extensions/apps/marketplaces/ |
extensions/apps/marketplaces/AGENTS.md |
src/auth/ |
src/auth/AGENTS.md |
frontend/ |
frontend/AGENTS.md |
src/capabilities/ |
src/capabilities/AGENTS.md |
Verification cadence
Complete CI tests and coverage run daily at 02:17 UTC or on explicit manual
workflow dispatch. Do not repeat the whole suite for every local commit or wait
for nightly results before continuing ordinary prototype work. Use targeted
checks for changed behavior; run full verification for explicit acceptance,
broad regressions or concrete failures requiring it. Required verify on PRs
and main pushes means short structure/governance checks, not complete test
acceptance. Preserve daily coverage floors and report the actual scope.