This is a reference implementation demonstrating how to build a SoftwareOne Marketplace Platform extension. The example is designed to be human-friendly with clear documentation and agent-friendly with well-structured code and comprehensive docstrings to enable effective code generation and analysis.
To develop/run this extension you can choose between two different options:
-
Docker (using compose.yaml)
- Build the app service:
docker compose build app
- Enter the bash shell of the container for development purposes:
docker compose run --rm bash
- Run the extension application:
docker compose run --rm app
- Build the app service:
-
Local machine
- Install Node.js: https://nodejs.org/en/download
- Install uv: https://docs.astral.sh/uv/getting-started/installation/
- In your vendor account, create a new extension
- In the extension detail view, navigate to the Service section and copy the Extension Secret
- Update the
settings.yamlfile with yourextension_idand setenv_domainif you target dev/test/staging - Create a
.secrets.yamlfile in the project root with the following content:api_key: <your-extension-secret>
Install frontend dependencies and build the bundles:
cd frontend
npm install
npm run buildScript details (from package.json):
build:types: Type-check and emit types usingtsc -p tsconfig.jsonbuild:code: Bundle JS/CSS usingnode esbuild.config.jsbuild: Runsbuild:typesthenbuild:codestart: Watch mode for local development (runs types + bundler in parallel)
Watch mode:
cd frontend
npm run startUse uv to create the virtual environment and install Python dependencies:
cd backend
uv syncStart the extension using:
runextOnce the extension started you can run the mrok Development Console to spy the traffic. In a new terminal window run:
mrok agent dev consoleYou can also run the web version or the development console:
mrok agent dev webThe complete repository structure has been moved to docs/project-structure.md to keep this README concise.
High-level layout:
backend/: FastAPI service and extension runtime logicfrontend/: UI source and build config (file layout may evolve)static/: generated frontend bundles served by backenddocs/: additional technical documentation- root config files:
meta.yaml,settings.yaml,compose.yaml,Dockerfile,identity.json
Backend (FastAPI)
main.py: Bootstrap entry point that initializes and runs the extension viarunextCLIextension.py: Declares the FastAPI application instance and mounts static file serving for frontend assetsapi.py: Defines API routes and webhook handlers for platform events and validationsconfig.py: Manages settings loading fromsettings.yamland environment variablesschema.py: Pydantic models for type-safe request/response validationauth.py: FastAPI dependency to inject the authentication context into the endpoint handlers.client.py: HTTPX based Marketplace API client with built-in support for authentication in the scope of an installation.
Frontend (Multi-Socket Architecture)
- Multiple entry points for different platform sockets (dashboard, accounts, settings, etc.)
- Each socket is compiled into a separate JavaScript bundle during the build process
esbuild.config.jshandles separate bundle generation for each socket- Built bundles are placed in
/staticfor serving by the backend
Configuration
meta.yaml: Jinja2 template declaring extension capabilities, hooks, events, and plugs. Supports dynamic values fromsettings.yamlsettings.yaml: Public configuration values (extension_id, product_id, API endpoints, domain settings). Defaults target production; changeenv_domainfor dev/test/staging..secrets.yaml: Sensitive data like API keys and secrets (must be created locally, never committed)
Deployment
Dockerfile: Container image for production deploymentcompose.yaml: Local development environment setup
- Adding Event Handlers — Subscribe to and process platform events
- Project Structure — Detailed repository layout and file organization
- Project Settings — Detailed docs about project settings.
