Create a New Lasso Service
This is the canonical handoff for creating a new release-backed service-lasso/lasso-* service repo.
For the recommended step-by-step authoring order, start with Service Authoring Overview. This page is the detailed implementation handoff for step 3, creating the release-backed service repo.
Use this guide when an agent or contributor needs to create a service from service-lasso/service-template, update an existing service repo, or decide how a consuming app should pin a service manifest.
Outcome
A complete service delivery produces:
- a dedicated GitHub repo in the
service-lassoorg, such aslasso-foo - a released
service.json - platform archives attached to a timestamped GitHub release
SHA256SUMS.txtwhen practical- local and CI validation that proves the archive can be installed and, where applicable, started by Service Lasso
- a pinned
services/<service-id>/service.jsoncommitted into each consuming app or into core when it is a core baseline service
Naming Rules
Repo names and service IDs are related, but they are not the same field.
| Thing | Rule | Example |
|---|---|---|
| GitHub repo | service-lasso/lasso-<name> | service-lasso/lasso-nginx |
| Core-owned service ID | @<name> | @nginx |
| Non-core app/service ID | no @ prefix unless the app owns that convention | echo-service |
| Service folder | must match the service ID | services/@nginx/service.json |
| Release tag | yyyy.m.d-<shortsha> from protected branch release workflow | 2026.4.28-b9cc74a |
Use the @ prefix only for core-owned Service Lasso services and providers such as @node, @python, @java, @localcert, @nginx, @traefik, and @serviceadmin.
Do not use @ for ordinary app services or test harnesses. echo-service is intentionally unprefixed.
Service Types
Choose the closest pattern before writing files.
| Type | When to use | Manifest shape |
|---|---|---|
| Provider | The service supplies a runtime/tool to other services and should not run as a daemon. | role: "provider" plus artifact and globalenv |
| Managed binary | The service owns and runs its executable. | artifact, platform command, ports, healthchecks[] |
| Provider-backed app | The service runs through another provider such as @node, @python, or @java. | execservice, executable, args, depend_on |
| App-owned add-on service | Consumers opt in by copying its released manifest. | enabled: false when unsafe to start without app config |
Required Repo Shape
Every lasso-* service repo should start from service-lasso/service-template, which provides this expected shape:
lasso-foo/
.github/
workflows/
release.yml
scripts/
lasso-foo.mjs
package.mjs
verify-release.mjs
service.json
README.md
LICENSE
package.json
Add service-owned runtime source or assets only when the service repo builds its own wrapper. Provider repos often package upstream archives instead. If setup needs cross-platform orchestration, prefer a service helper at scripts/lasso-<service>.mjs; keep each setup step declared in service.json and let the helper implement focused subcommands. Use Setup Helper Conventions for the full pattern and the platform-script fallback.
service.json Minimum Contract
Every released service manifest must include:
idnamedescriptionversionenabledartifact.kind: "archive"artifact.source.type: "github-release"artifact.source.repoartifact.source.tagartifact.platforms.<platform>.assetNameartifact.platforms.<platform>.archiveTypeartifact.platforms.<platform>.commandwhen the archive exposes an executable
Managed services should also declare:
portsurlshealthchecks[]envandglobalenvwhere operator or dependent services need resolved valuesinstall.filesorconfig.fileswhen Service Lasso must materialize runtime configdepend_onwhen startup requires another service firstsetup.stepswhen install/config must run idempotent one-shot helper commands before start
Provider services should declare:
role: "provider"globalenventries that expose installed tool paths through${SERVICE_ARTIFACT_COMMAND}and${SERVICE_ARTIFACT_ROOT}- a cheap version/probe command in platform
args
Use SERVICE_ROOT as the canonical service package root in service-local env, setup, config, commandline, and healthcheck selectors. SERVICE_PATH is available as a compatibility alias for authoring examples that use package-path wording. Provider-level names such as NODE_HOME, PYTHON_HOME, and PYTHON_SCRIPTS_PATH must be exported by the provider service through globalenv; ordinary services should not assume those names exist unless they depend on the provider that publishes them.
Setup Helper Convention
When setup work is longer than a small command, keep service.json declarative and put service-specific orchestration in helper code.
Preferred Node-backed layout:
lasso-foo/
scripts/
lasso-foo.mjs
service.json
Typical subcommands:
node scripts/lasso-keycloak.mjs generate-keystore
node scripts/lasso-keycloak.mjs ensure-database
node scripts/lasso-keycloak.mjs build
Bind those subcommands from manifest-visible setup steps:
{
"depend_on": ["@node", "postgres"],
"setup": {
"steps": {
"ensure-database": {
"description": "Create the service database and role when missing.",
"execservice": "@node",
"cwd": "${SERVICE_ROOT}",
"commandline": "scripts/lasso-foo.mjs ensure-database",
"depend_on": ["postgres"],
"timeoutSeconds": 120,
"rerun": "ifMissing"
}
}
}
}
Use the Node helper pattern only when the service already requires Node or can declare the @node provider. When Node should not be required, use platform scripts under scripts/setup/*.ps1 and scripts/setup/*.sh instead. In both cases, the helper or scripts must be idempotent, poll bounded readiness signals, return accurate exit codes, avoid leaking secrets, and log enough context for operators to diagnose failures. See Setup Helper Conventions for the detailed contract.
Managed Binary Example
{
"id": "@nginx",
"name": "NGINX",
"description": "Release-backed NGINX Open Source service.",
"version": "1.30.0",
"enabled": true,
"ports": {
"http": 18080
},
"artifact": {
"kind": "archive",
"source": {
"type": "github-release",
"repo": "service-lasso/lasso-nginx",
"tag": "2026.8.12-f587add"
},
"platforms": {
"win32": {
"assetName": "lasso-nginx-1.30.0-win32.zip",
"archiveType": "zip",
"command": ".\\nginx.exe"
},
"linux": {
"assetName": "lasso-nginx-1.30.0-linux.tar.gz",
"archiveType": "tar.gz",
"command": "./sbin/nginx"
}
}
},
"healthchecks": [
{
"id": "http-health",
"type": "http",
"url": "http://127.0.0.1:${HTTP_PORT}/health",
"expected_status": 200
}
]
}
Provider Example
{
"id": "@node",
"name": "Node Runtime",
"description": "Release-backed Node.js runtime provider.",
"version": "v24.15.0",
"role": "provider",
"enabled": true,
"globalenv": {
"NODE": "${SERVICE_ARTIFACT_COMMAND}",
"NODE_HOME": "${SERVICE_ARTIFACT_ROOT}"
},
"artifact": {
"kind": "archive",
"source": {
"type": "github-release",
"repo": "service-lasso/lasso-node",
"tag": "2026.4.27-eca215a"
},
"platforms": {
"win32": {
"assetName": "lasso-node-v24.15.0-win32.zip",
"archiveType": "zip",
"command": ".\\node.exe",
"args": ["--version"]
}
}
}
}
Artifact Naming
Artifact names must be predictable and must include the packaged upstream version when the service wraps third-party software.
Use:
lasso-node-v24.15.0-win32.ziplasso-java-17.0.18+8-linux.tar.gzlasso-python-3.11.5-win32.ziplasso-nginx-1.30.0-darwin.tar.gz
Do not use vague names such as:
node-win32.ziplasso-node-24-win32.ziplatest.zip
When the service is your own app and the upstream/tool version is the service release itself, use a stable service asset name such as echo-service-win32.zip and rely on the GitHub release tag for the package release version.
Release Workflow Rules
Service repos should release on protected-branch pushes, not manual tags.
Release tags must use:
yyyy.m.d-<shortsha>
Each release should attach:
- one archive per supported platform
- the exact released
service.json SHA256SUMS.txtwhen practical
If a platform is not supported, omit that platform from artifact.platforms and document the unsupported state in the repo README.
Local Validation
Before opening the service repo PR, prove:
- The package script creates every documented archive.
- The archive contains the command path declared in
service.json. - The command runs with the declared version/probe args.
service.jsonpoints at the intended repo, release tag, artifact names, and archive types.npm testor the repo's equivalent validation passes.
For a managed service, also prove:
- Service Lasso can install/acquire the archive.
- Service Lasso can config/start/stop the service.
- The declared required healthcheck becomes healthy.
- Logs/state/network surfaces are visible when the service claims them.
Core Integration
Only update core services/ after the service repo has a verified release.
Core integration steps:
- Copy or adapt the released manifest into
services/<service-id>/service.json. - Pin
artifact.source.tagto the verified release tag. - Keep
versionas the service or upstream runtime version, not the Service Lasso release tag, unless they are intentionally the same. - Add or update manifest discovery tests if the service is part of core inventory.
- Add live verifier coverage when the service is part of the baseline or a critical provider path.
- Run
npm run build. - Run targeted tests for manifest/provider/lifecycle behavior.
- Run
npm run verify:baseline-startwhen the service is part of the default baseline. - Run
npm testbefore claiming the core change is complete.
Default baseline services currently are:
@archive@java@localcert@nginx@traefik@node@pythonwhere the pinned provider release supports the host platform; unsupported hosts get an explicit baseline skip until the provider repo publishes matching artifacts@secretsbrokerecho-service@serviceadmin
Non-baseline provider and app-owned manifests such as zitadel, keycloak, and dagu should not be added to default baseline start unless the app has the needed config and dependencies.
Consumer Integration
Apps that use Service Lasso own their services/ folder.
To add a service to an app:
- Create
services/<service-id>/service.json. - Copy the released manifest from the service repo.
- Keep
artifact.source.repo,artifact.source.tag, and platformassetNamevalues pinned. - Adjust app-owned ports, env, URLs, and dependencies as needed.
- Run the app's source/bootstrap artifact verification.
- Run bundled/no-download artifact verification if the app publishes bundled outputs.
Bundled means Service Lasso packaging has already acquired the configured archives into the app artifact so the user does not download them on first start.
Documentation Requirements
Each new service repo README must state:
- service ID
- repo/release relationship
- supported platforms
- artifact names
- upstream project and upstream version when applicable
- required app-owned environment variables
- ports and healthchecks
- install/config/start behavior
- validation commands
- known unsupported platforms or deferred behavior
Update core docs when the rule is general. Keep service-specific quirks in the service repo.
Agent Checklist
Use this checklist before handing off:
- GitHub issue exists with spec binding and acceptance criteria.
- Branch starts from the correct target branch.
- Repo name follows the
service-lasso/lasso-<name>pattern. - Service ID follows the prefix rule.
service.jsonhas artifact download metadata in the manifest itself.- Setup helper layout, provider/runtime dependencies, idempotence, logging, and secret-handling rules are documented when setup delegates to helper code.
- Release workflow creates
yyyy.m.d-<shortsha>releases from protected-branch pushes. - Artifact names include exact upstream versions when applicable.
- Released archive paths match platform
commandvalues. - Local verification passes.
- CI release workflow passes.
- Core/reference manifests are updated only after release proof exists.
- PR is merged into the correct target branch.
- Work branch is archived as
archived/<issue-and-slug>. - Local checkout returns to the clean target branch.