Lightbulb SDK and MCP
Python SDK, MCP server, and helper CLI for the Lightbulb Partners Agents platform. Build typed business process primitives and custom project workflows, or connect Claude Code, Codex, or Cursor to Lightbulb domain agents, workspaces, connectors, builders, approvals, and AutoCompany.
Product boundary: this release line is suitable for controlled internal pilots. It is not yet a generally available external developer platform, and a locally verified capability is not a production-certified provider outcome. Spring remains the sole authority for tenant scope, RBAC, approvals, credentials, and live writes. See STABILITY.md for the support and deprecation policy.
For the MCP host integration details (authentication, tool surface, troubleshooting), see MCP.md. For partner-facing setup, governance, and hosted MCP guidance, see the Lightbulb Partners Docs: https://agents.lightbulbpartners.com/partners/docs
Starting in 0.14, Connector Execution, executable primitives, durable custom-project runtime contracts, runtime telemetry, and connector conformance are supported SDK surfaces. The broad endpoint client remains beta.
AsyncLightbulbClientprovides complete behavioral parity, with hot paths async-native and long-tail methods thread-forwarded. Pin a minor version for production projects.
One governed developer journey
Use the SDK through one five-step path:
- Declare a typed primitive or Company Blueprint and select its exact version.
- Validate it and preview it locally with external effects disabled.
- Publish the immutable definition digest; publication does not grant effect authority.
- Start or resume the exact hosted run, where Spring resolves scope, permission, approval, idempotency, and any Connector Tool Binding.
- Observe sanitized events, evidence references, and the terminal outcome; treat missing or ambiguous provider observation as unresolved, never as success.
The compact seven-operation Golden Loop protocol is the primary model-facing interface. Raw domain and connector operations are an advanced surface and do not bypass the same Spring authority.
Curated SDK namespaces
New code should use the small lazy namespaces instead of adding package-root imports:
from lightbulb.core import JwtAuth, PermissionDenied
from lightbulb.hosted import AsyncLightbulbClient, LightbulbClient
from lightbulb.runtime import BusinessProcessPrimitive, ExecutablePrimitiveRuntime
from lightbulb.domains.finance import (
PrepareJournalEntryInput,
ReconcileJournalPostResult,
)
lightbulb.core and lightbulb.runtime are Supported. lightbulb.hosted and
lightbulb.domains.finance are Beta; pin the SDK minor version. Importing a
namespace is lazy and does not import its owning implementation modules. The
finance namespace is the bounded journal-to-close lighthouse contract, not
live-write authority: provider-backed operations remain quarantined until the
exact capability version has current Spring-owned certification evidence.
Install
Installs the lightbulb-mcp package directly from the public GitHub repo:
pip install git+https://github.com/RPasquale/lightbulb-mcp.git
lightbulb version
Console scripts:
lightbulb-mcp— runs the MCP server over stdio for Claude Code / Codex / Cursor (see MCP.md).lightbulb— helper CLI for status, login, and one-shot platform commands.
Quick start — wire up Claude Code
pip install git+https://github.com/RPasquale/lightbulb-mcp.git
lightbulb setup
lightbulb version
lightbulb setup is an interactive wizard: device-flow login (browser handles MFA), probe /api/users/me, then merge a lightbulb MCP server entry into Claude Code (.mcp.json / .claude.json), Codex (~/.codex/config.toml), or Cursor (~/.cursor/mcp.json). For Claude Code it also installs Lightbulb Continuum lifecycle hooks in ~/.claude/settings.json (user target) or .claude/settings.json (project target). Existing servers, Claude settings, and unrelated hooks are preserved; backups use .bak.
Targets include --target claude-code-user, --target claude-code-project,
and --target codex; setup also accepts --yes / --no-write,
--skip-login, and --url.
Manual .mcp.json
If you'd rather wire Claude Code by hand:
{
"mcpServers": {
"lightbulb": {
"command": "lightbulb-mcp",
"env": {
"LIGHTBULB_URL": "https://agents.lightbulbpartners.com",
"LIGHTBULB_MCP_PROFILE": "adaptive"
}
}
}
}
The MCP server resolves credentials from a cached device-flow token (~/.lightbulb/tokens/) by default, or from env (LIGHTBULB_JWT + LIGHTBULB_TENANT_ID, etc.). Full auth precedence in MCP.md.
Lightbulb Continuum for Claude Code
The installed Claude hooks open or resume a private Context Space at session
start, load a bounded relevant context pack with each user prompt, and
checkpoint prompt, assistant, and compaction-boundary events. This gives
Claude Code durable searchable working history; it does not change Claude's
native context-window limit. Run /hooks in Claude Code to inspect the active
hooks.
Each Context Space has a default 10,000,000-token indexed-storage ceiling. The
host still receives only a small prompt-aware pack (up to its requested bounded
budget); it can search and read deeper evidence by opaque reference. In other
words, Continuum virtualizes a much larger working set behind the model rather
than pretending the provider accepted a 10-million-token prompt. Repository
continuity fingerprints let Codex and Claude Code resume the same private space
without uploading a raw repository path or remote URL; an explicit
LIGHTBULB_CONTEXT_REF can link other sessions.
At the storage ceiling, automatic capture changes to read-only mode while pack,
search, and read continue; a rejected append never disables recall of the full
existing corpus.
For user custody and lifecycle control, the SDK exposes context_export(...),
context_archive(...), and context_delete(...). Export is cursor/item/byte
bounded; deletion is exact-scope and enters the server's grace-period purge
workflow. These destructive lifecycle controls are intentionally not delegated
to the model-facing MCP tool catalog.
Set LIGHTBULB_CONTEXT_CAPTURE=0 to disable all automatic capture, or
explicitly set LIGHTBULB_CONTEXT_CAPTURE_TOOLS=1 to opt into storing redacted
tool inputs and outputs. Tool capture is off by default because tool results can
contain credentials or company-scoped data. Re-running lightbulb setup
updates only Lightbulb's own handlers and leaves other Claude hooks intact.
To share one project-scoped Continuum across supported coding harnesses, run
lightbulb setup --context-company-ref <company:...> --context-project-ref <project:...> for each host. Both selectors are rename-stable public refs and
are reauthorized against the signed-in account on every hook invocation.
When hooks are disabled or unavailable, the local stdio context_* MCP tools
accept the same optional company_ref + project_ref pair and resolve it
through authenticated discovery; they never accept tenant/user/internal-ID
scope from the model.
Cross-harness Dynamic Workflows
Protocol 1.4 gives Claude, Claude Code, Codex, ChatGPT, and the Lightbulb
harness one durable planner → builder → fresh-evaluator loop. The sync and
async clients expose exactly eight operations:
dynamic_workflow_start, dynamic_workflow_attach,
dynamic_workflow_status, dynamic_workflow_next_assignment,
dynamic_workflow_submit_plan, dynamic_workflow_submit_builder_result,
dynamic_workflow_submit_evaluator_verdict, and
dynamic_workflow_cancel. The stdio and hosted HTTP MCP surfaces delegate
those operations to the same Spring authority; neither keeps a competing local
hosted checkpoint.
Every mutation is exact-project scoped, revision-checked, idempotent, and receipt-bound. Evaluator acceptance defaults to failure and requires a binding distinct from the builder. MCP session separation is reported honestly as transport assurance; only a Lightbulb-controlled executable runtime can issue the stronger fresh-model-context attestation.
CLI
Running lightbulb with no arguments prints status: platform URL, cached token hint, detected Claude/Codex/Cursor configs, and next steps.
lightbulb # status (default)
lightbulb setup # guided auth + MCP config merge
lightbulb version # installed package version
lightbulb whoami
lightbulb dispatch finance --action chat --message "Quick AR aging summary"
lightbulb search-documents "quarterly revenue" --top-k 5
lightbulb approvals list
Environment variables (CLI & MCP)
| Variable | Purpose |
|---|---|
LIGHTBULB_URL |
Platform base URL (default https://agents.lightbulbpartners.com) |
LIGHTBULB_JWT |
Bearer JWT |
LIGHTBULB_TENANT_ID |
Required with JWT |
LIGHTBULB_COMPANY_ID |
Optional company scope |
LIGHTBULB_EMAIL / LIGHTBULB_PASSWORD |
Legacy password login |
LIGHTBULB_API_KEY / LIGHTBULB_USER_ID |
Localhost integration bootstrap |
LIGHTBULB_MCP_PROFILE |
Optional MCP profile. adaptive is the four-tool, on-demand default; sovereign adds the preview-locked Local capability catalog. Read and action invokers are separate so MCP hosts can enforce risk policy before a call. |
LIGHTBULB_LOCAL_RUNTIME_SECURITY_PROFILE |
Set to sovereign by Local setup. Activates fail-closed endpoint, proxy, tool-surface, and authentication boundaries. |
LIGHTBULB_HOOK_AUTH_ORIGIN |
Optional exact HTTP(S) origin binding for ambient hook credentials in sovereign mode. When unset, lifecycle hooks ignore ambient JWT/API/password credentials and use the protected token cache for the configured customer URL. |
LIGHTBULB_CONTEXT_CAPTURE |
Set to 0 to disable automatic Continuum capture in Codex and Claude Code hooks. |
LIGHTBULB_CONTEXT_CAPTURE_TOOLS |
Set to 1 to opt into redacted tool-event capture. Default 0; prompt/response continuity remains active. |
LIGHTBULB_CONTEXT_COMPANY_REF + LIGHTBULB_CONTEXT_PROJECT_REF |
Optional public refs that pin automatic Continuum hooks to one authenticated hosted project. Configure both; setup resolves them through the signed-in account and never accepts a model-supplied scope. |
LIGHTBULB_CONTEXT_COMPANY_ID |
Legacy trusted local-only company scope for a personal Context Space when no project refs are configured. Prefer the public-ref pair above for project continuity. |
LIGHTBULB_ENABLE_PRIVATE_RUNTIME_ACTION_MCP |
Trusted local-developer opt-in for the three UUID-backed runtime-action MCP tools. Default false; never use on a hosted/OpenAI-facing surface. |
LIGHTBULB_ENABLE_PRIVATE_PROJECT_LEARNING_MCP |
Trusted non-public operator opt-in for the three Project learning preparation/admission mutation tools. Default false; the compact backbone profile always excludes them. |
LIGHTBULB_MCP_NAMESPACES |
Optional comma-separated allow-list of generated-tool namespaces (e.g. finance,crm,gmail). Hand-written control-plane tools always register. Unset = full non-private generated surface. Exact current counts come from ../api-specs/lightbulb.capability-inventory.v1.json, not this README. |
LIGHTBULB_RUNTIME_OUTCOMES_FILE |
Optional JSONL queue shared by SDK execution and improve-workflows; when unset, each client uses bounded in-memory telemetry. |
Backbone-first profile for OpenAI hosts
For Codex plugins and other OpenAI-facing installs, use the compact backbone profile:
{
"mcpServers": {
"lightbulb": {
"command": "lightbulb-mcp",
"env": {
"LIGHTBULB_URL": "https://agents.lightbulbpartners.com",
"LIGHTBULB_MCP_PROFILE": "adaptive"
}
}
}
}
This profile exposes the Lightbulb control plane rather than every generated domain/connector tool: identity and company selection, the backbone agent, approvals, connector status, workspace context, and the software delivery loop. The backbone agent can still orchestrate domain agents under the user's normal tenant, company, RBAC, and approval rules.
Governed runtime domain actions
The sync and async clients expose an explicit project-scoped lifecycle for runtime ACTION registration:
from lightbulb import RecursiveAgentPolicy
client.active_company_id = company_id
pending = client.register_runtime_domain_action(
"finance",
"review_invoice",
project_id=project_id,
idempotency_key="runtime-action:review-invoice:v1",
component_ids=["finance-dashboard"],
agent_spec={
"name": "Invoice reviewer",
"system_prompt": "Review invoices and return evidence.",
"allowed_tools": ["xero.list_invoices"],
"model": "gpt-5-mini",
"domain": "finance",
},
execution_policy={"max_iterations": 3, "max_output_tokens": 512},
)
review = client.get_runtime_domain_action(pending["id"], project_id=project_id)
# After explicit human review, an authorized ADMIN/TENANT SDK client may approve.
approved = client.approve_runtime_domain_action(review["id"], project_id=project_id)
assert approved["status"] == "approved"
assert approved["recursive_spawnable"] is True
# Approval does not activate ordinary domain dispatch. Provision this exact,
# opaque revision only for a finite recursive run.
policy = RecursiveAgentPolicy(
max_depth=2,
max_total_nodes=4,
max_cost_usd=1.00,
max_delegation_context_bytes=4096,
max_total_delegation_context_bytes=16384,
allowed_agent_ids=(approved["recursive_agent_id"],),
)
result = client.recursive_agent_execute(
"Review the selected project's invoices and state missing evidence.",
inputs={"project_id": project_id},
policy=policy,
)
Registration requires a selected company, an explicit project UUID, and a
caller-owned idempotency key of 1-128 visible ASCII characters. Scope, status,
owner, workflow selection, version, digest, and idempotency fields are never
accepted in the JSON body. This first contract is immutable v1-only; changing a
registered action requires a future revision lifecycle rather than mutating it.
Authored specs use only name, system_prompt, allowed_tools, model, and
domain; prompts are capped at 16,000 characters, specs at 32 KiB, and tool
allow-lists at 16 entries. The example uses a seeded active read-only tool;
replace it only with dotted tool names discovered as active in the platform
registry. Execution policy accepts only bounded iteration,
output-token, runtime, and cost values. Register always lands as
pending_approval; list/get are review reads, and approve/reject are separate
permissioned SDK transitions. Approval lands in approved and remains absent
from ordinary domain dispatch. An approved dynamic-agent workspace response now
includes recursive_agent_id plus recursive_spawnable; only that opaque
revision may be named in an explicit finite recursive policy. During root
preflight and before any authored child can spawn, the worker performs one
Spring resolution that rechecks the
current actor, exact tenant/company/project access, component RBAC, approval,
revision digest, and execution policy. The run then freezes the spec and the
intersection of its approved tools with the root's provisioned tool catalog.
When a parent delegates, agent.spawn_child and agent.spawn_children accept an
optional delegation_context JSON object. Parents should select only the facts,
constraints, evidence references, decisions, open questions, and success
criteria the child needs. Lightbulb deterministically compacts each packet,
binds it to the inherited scope, returns a digest/compaction receipt without the
packet contents, and atomically charges it against both policy byte ceilings.
Child prompts label the packet as untrusted task data rather than instructions.
Runtime-authored children cannot delegate, cannot poll the mutable control
plane, and fail closed on unresolved scope, model substitution, or integrity
drift. The durable tree enforces finite node/depth/token/cost/deadline limits,
and authored children additionally clamp model, tools, runtime, iteration,
output-token, and cost authority. The pinned Codex app-server has no request
fields for max_iterations or max_output_tokens, so the worker enforces them
as an online outer guard: it consumes the exact per-call last values from
thread/tokenUsage/updated, interrupts the turn at the approved boundary, and
closes the per-node app-server process before another ungoverned run can be
reused. Token/cost authority comes from the private atomic tree rollout
allocation; the model-visible node budget is only a consistency check and
cannot increase it. Missing/malformed telemetry or a changed SDK observation
hook fails closed. Because one provider response is already in flight when its
usage becomes observable, that response can overshoot a token or estimated-cost
boundary; the lightbulb.codex_turn_resource_guard.v1 receipt records the observed usage
and overshoot. Guard cost is an explicitly conservative estimate that charges
all input at the uncached rate and applies a 1.25 safety multiplier. Each node
retains at most 16 raw usage notifications, and
an incomplete result returns partial with
finish_reason=resource_limit. There is no end-user runtime-action review UI
yet.
The UUID-backed register/list/get MCP tools are excluded by default and always
excluded from the compact, OpenAI-facing Backbone profile. A trusted,
non-public local developer surface must set
LIGHTBULB_ENABLE_PRIVATE_RUNTIME_ACTION_MCP=true to expose them. None of these
lifecycle methods directly dispatches or executes the action. SDK responses retain the server's snake-case
scope/version/digest fields; registration also reports idempotent_replay and
returns the same resource on an exact replay.
Deployment invariant: V1709 is additive at the schema level, but this feature
is not safe across mixed application versions. Keep
AGENTS_RUNTIME_REGISTRATION_ENABLED=false until every pre-V1709 server is
drained, and disable it before any rollback to a pre-V1709 binary.
Success-aware least-active-memory regulation
The sync and native async clients can preview or execute active-memory regulation with an empirical success-evidence floor:
preview = client.memory_regulate(
budget=500,
dry_run=True,
empirical_success_floor_ppm=950_000,
empirical_success_min_samples=40,
empirical_success_lookback_days=90,
optimize_for_least_active_memory=True,
)
The server counts only exact-owner Memory references from retained successful
skill-execution receipts and selects the smallest budget that clears the floor.
It rejects insufficient, over-limit, or below-floor evidence before a
consequential mutation. The returned quality gate says
empirical_reference_retention_not_task_success: compacted digests receive no
credit, and this is not a substitute for a held-out task-success evaluator.
Mutating calls still require a caller-owned idempotency_key; the MCP tool is
preview-only. The monorepo architecture note
docs/memory-success-aware-regulation.md defines the metric and authority
contract.
For held-out task quality, first request exact virtual candidate bindings:
preview = client.memory_regulate(
budget=500,
dry_run=True,
optimize_for_least_active_memory=True,
held_out_task_evaluation={
"task_success_floor_ppm": 850_000,
"minimum_sample_count": 200,
"candidate_budgets": [100, 200, 300, 500],
"authenticated_receipts": [],
},
)
A trusted evaluator runs the same held-out cohort against the baseline and each
returned candidate, then the mutating SDK call supplies its aggregate signed
receipts plus an idempotency_key. The server recomputes the current source and
candidate plans, rejects drift or any failed success/safety/cost gate, and
selects the least active eligible candidate. Empirical reference evidence and
held-out task evaluation are mutually exclusive in one request. See
docs/memory-held-out-regulation.md; production verification is unavailable
until the purpose-specific evaluator key and exact evaluator identities are
provisioned.
Governed account-shell customization
The sync and async clients expose the tenant-scoped account-shell lifecycle: read, draft, preview, explicit publish, immutable history, and rollback. MCP exposes only read, draft, and preview so an agent can propose a change without crossing the human publication boundary.
New component placements should use component_version: 2. The closed
registry fixes the React implementation and route. A document can set only
emphasis, a narrowing page_scope (any, tenant, or company), and the
exact registry capability with operation: navigate:
client.create_account_shell_customization_draft({
"schema": "lightbulb.frontend_customization.v1",
"surface": "account_shell",
"name": "Operations",
"tokens": {"colors": {"primary": "#315efb", "secondary": "#6366f1"}},
"components": [{
"component_id": "projects_launcher",
"component_version": 2,
"region": "header_actions",
"props": {
"emphasis": "primary",
"visibility": {"page_scope": "company"},
"action": {
"capability_id": "service.projects-workspace",
"operation": "navigate",
},
},
}],
}, base_revision_id=None)
Historical version-1 placements remain readable. Rendering still checks the current viewer's service/RBAC capability; a stored placement never grants access. Routes, URLs, scripts, event handlers, raw CSS, Tailwind code, and iframes are rejected rather than interpreted.
Business primitives and Agent Builder
search_agent_marketplace is the normalized discovery front door for both
action listings and domain-worker listings. It keeps business primitives and
domain actions as distinct stable IDs, exposes only whitelisted contract
metadata, and reports undeclared price/evaluation/risk fields as unknown rather
than guessing. Without a domain filter, domain contracts are global discovery
metadata and remain unverified. With a domain filter, the SDK performs one
authenticated action lookup for that domain and marks only returned rows
rbac_visible—never executable. Dispatch still re-checks tenant, selected
company, RBAC, plan entitlement, connectors, and HITL policy.
The same contract is available from sync and async Python clients through
search_agent_marketplace(...) and from the compact Backbone MCP profile.
These discovery rows use stable synthetic IDs, not persisted UUIDs. Every row
therefore reports installable=false, lifecycle_installable=false, and the
stable reason synthetic_discovery_listing_not_persisted. Never pass a
synthetic ID to install, pin, or invoke methods.
Publishing a governed action
Publication is tenant-scoped and must start with a preview. The preview resolves an existing server-authoritative action contract and returns the digest for the exact contract bytes the server would publish. Pass that digest back on publish as a compare-and-set guard:
publication = {
"slug": "invoice-drafter",
"name": "Invoice Drafter",
"version": "1.0.0",
"domain": "finance",
"action": "create_invoice",
"visibility": "PRIVATE",
"pricing_model": "INCLUDED",
"changelog": "Initial governed release",
}
preview = client.preview_marketplace_action_publication(**publication)
if not preview["publishable"]:
raise RuntimeError(preview["blockers"])
published = client.publish_marketplace_action(
**publication,
expected_contract_digest=preview["expected_contract_digest"],
idempotency_key="publish-invoice-drafter-1.0.0",
)
final = client.wait_for_marketplace_action_publication(
published["publication_id"],
timeout_seconds=120,
)
client.archive_marketplace_action(
published["listing_id"],
idempotency_key="archive-invoice-drafter",
reason="Superseded",
)
The publication allowlist is slug, name, version, domain, action,
visibility, pricing_model, and changelog; publish adds only
expected_contract_digest. Raw manifests, agent or worker packages, prompts,
models, tool policies, and scope IDs are not accepted. PRIVATE is the default.
Shared UNLISTED or PUBLIC publication requires a portable platform contract,
and PUBLIC is publisher-tier gated. Only INCLUDED pricing is implemented;
there is no checkout publication path.
Use get_marketplace_action_publication(publication_id) for one status read, or
the bounded wait_for_marketplace_action_publication(...) helper to poll until
ready, failed, or archived; an initial scanning response can accompany
an already-succeeded publication operation. Publish and archive are replay-safe
only when each request carries a stable idempotency key. Archive preserves
immutable revisions and audit history and does not uninstall existing company
installations.
All five method names are identical on LightbulbClient and
AsyncLightbulbClient (await the async calls):
preview_marketplace_action_publication, publish_marketplace_action,
get_marketplace_action_publication,
wait_for_marketplace_action_publication, and
archive_marketplace_action.
The Backbone MCP names are
preview_agent_marketplace_action_publication,
publish_agent_marketplace_action,
get_agent_marketplace_action_publication, and
archive_agent_marketplace_action. MCP has no wait tool; poll with its get tool.
Persisted marketplace actions use a separate, server-authoritative lifecycle:
start with list_marketplace_listings(...) (or the MCP tool
list_agent_marketplace_listings) and use the returned UUID listing_id and
revision_id.
listings = client.list_marketplace_listings(kind="action")
listing = listings["items"][0]
installed = client.install_marketplace_action(
listing["listing_id"],
listing["revision_id"],
idempotency_key="install-invoice-drafter-2026-07-10",
deployment_targets=["codex_backbone", "claude_code_domain:finance"],
)
installation_id = installed["installation"]["installation_id"]
# Installation is deliberately inactive until a separate governed decision.
client.activate_marketplace_action(
installation_id,
idempotency_key="activate-invoice-drafter-2026-07-10",
)
preview = client.invoke_marketplace_action(
installation_id,
{"invoice_id": "invoice-123"},
dry_run=True,
idempotency_key="preview-invoice-123",
)
# Live execution is fail-closed unless it binds the exact successful preview
# and the caller explicitly confirms the reviewed request.
live = client.invoke_marketplace_action(
installation_id,
{"invoice_id": "invoice-123"},
dry_run=False,
preview_invocation_id=preview["invocation_id"],
confirm_live=True,
idempotency_key="invoke-invoice-123",
)
The tenant is derived from authentication and the company from the selected
company header; neither is accepted in lifecycle request bodies. Every mutation
and invocation requires an idempotency key. Invocation defaults to dry-run;
live execution requires the successful preview ID for the exact inputs plus an
explicit confirmation. Installs pin one immutable scanned
revision, activation never auto-approves a separate HITL task, and receipts bind
the exact installation, revision digest, request hash, trace/workflow IDs, cost
state, and bounded redacted output. Use the matching async methods on
AsyncLightbulbClient.
deployment_targets is an optional sequence of governed agent bindings. Its
canonical vocabulary is codex_backbone, claude_code_domain (all Claude Code
domain agents), and claude_code_domain:<domain> (for example,
claude_code_domain:finance). The client rejects unsupported values and allows
at most 16 unique targets. Omitting the argument, passing None, or passing an
empty sequence installs the action for direct lifecycle invocation only; it is
not projected into an agent's automatic tool catalog. The same argument and
semantics apply to AsyncLightbulbClient.install_marketplace_action(...).
Worker listings remain discovery-only and report installable=false until a
signed package, runtime ABI, SBOM, isolation declaration, and attestations exist.
Governed training-pair readiness (no launcher)
The SDK exposes the bounded Spring agent-ops gateway for one active company's exact pinned marketplace action revision:
readiness = client.inspect_training_pair_readiness(
installation_id,
listing["revision_id"],
project_id=project_id, # optional exact-scope constraint
)
# Inspect the server-derived custody association. A verified response contains
# only a bounded receipt summary; it is evidence, not training readiness.
custody = client.inspect_training_pair_input_custody(
installation_id,
listing["revision_id"],
project_id=project_id,
)
# The backward-compatible flat preflight remains available.
preflight = client.preflight_training_pair(
installation_id,
listing["revision_id"],
project_id=project_id,
)
# This is an explicit request, not a successful admission. Production returns
# the structured lightbulb.training_pair_admission.v1 body with HTTP 503.
unavailable = client.request_training_pair_admission(
installation_id,
listing["revision_id"],
project_id=project_id,
idempotency_key="training-pair-invoice-drafter-1",
)
# Only a previously persisted, exact-owner pair with an immutable marketplace
# source row can be read. Archived retained projects remain readable.
status = client.get_training_pair_status(pair_handle, project_id=project_id)
The same method names exist on AsyncLightbulbClient. Every call requires a
valid selected company. Request bodies contain only installation_id,
revision_id, and optional project_id; tenant, company, and actor authority
come from authentication and server-side RBAC. Admission additionally requires
a 1-200 character visible-ASCII Idempotency-Key. Preflight and status are
read-only. Structured readiness returns exact source validity, ordered authority
stages, blocked puffer_v4 and prime_verifiers lanes, and one next action.
It cannot report admission or execution authority. Status is privacy-minimized
and does not return datasets, artifacts,
receipts, secrets, or storage locations.
Input-custody inspection is also read-only. The server derives the exact owner
and associated receipt; callers cannot provide an owner binding, receipt,
storage handle, tenant, company, or actor. The strict
lightbulb.training_pair_input_custody.v2 response reports one of five states:
authority_unavailable, not_associated, verification_failed, expired, or
verified. Only verified includes a privacy-minimized receipt summary with
digests, counts, timestamps, cost, the pinned framework commit for both lanes,
and the aggregate signed snapshot binding/dataset identity needed for exact
workflow-learning reconciliation. It never returns raw receipt evidence,
signatures, storage locations, or lane artifact/partition digests, and it
always reports admission and execution as unavailable.
The target-company policy overlay is fail-closed. COMPANY has read-only
preflight/status access by default and needs an explicit company-scoped
agent-ops.training.execute grant for admission requests. The structured 503
is reached only after authentication, target-company RBAC, idempotency-key,
project-scope, and marketplace-source validation succeed. It is not an auth or
validation fallback.
This is not a training runtime. There is no production admission assembler,
scheduler, launcher, or worker persistence/install lifecycle. The gateway's six
authoritative blockers are training_profile_unavailable,
budget_authority_unavailable, snapshot_authority_unavailable,
scheduler_unavailable, metering_unavailable, and
artifact_storage_unavailable. The SDK preserves only that exact structured
hard-503 admission body; unrelated errors and schema mismatches raise normally.
The newer structured-readiness schema additionally reports
input_attestation_unavailable because Spring has no trusted production input
attestation authority wired to the offline dual-lane registry.
The matching MCP tools are inspect_agent_learning_readiness,
inspect_agent_training_input_custody, preflight_agent_training_pair,
request_agent_training_pair_admission, and get_agent_training_pair_status.
The compact Backbone profile exposes custody inspection instead of the
currently impossible admission request; the full profile retains the guarded
admission tool for compatibility.
The admission tool first returns a v2 request-bound confirmation receipt. After
an explicit user request, return that exact confirmation_receipt together with
confirm_admission_request=true. The receipt binds installation, revision,
optional project, and the idempotency-key digest, so a bare boolean cannot be
reused for a different future live request. The server still performs zero
writes today.
Lightbulb MCP exposes business primitives as backend Lego blocks over the existing domain-agent and connector surface:
list_business_primitivesdiscovers primitives such as invoices, supplier invoice intake, email, contracts, meetings, lead qualification, and onboarding.run_business_primitiveis the canonical MCP entry to the same versionedExecutablePrimitiveRuntimeused by the SDK. The Python surface executes locally eligible implementations; the hosted surface resolves authenticated company/project scope and fails closed until its managed Python runtime bridge is available. It never substitutes a Backbone workflow for primitive execution.list_executable_business_primitivesdiscovers primitive implementation code shipped in the Python package, including exact typed input/output schemas.run_sdk_business_primitiveis the explicit compatibility alias for that same runtime and remains useful for typed local validation and preview. A caller-provided project, approval, or idempotency value cannot turn a preview into a live write. Consequential effects must return through Spring's governed Connector Execution authority; neither primitive entry point self-authorizes.compile_business_workflowcreates a portablelightbulb.business_workflow_definition.v1draft from selected primitives.validate_business_workflowchecks primitive order, scope, RBAC, hidden setup, approval gates, state transitions, recovery, and test coverage.simulate_business_workflowdry-runs one synthetic iteration without agents, connectors, network calls, or external writes.compose_business_workflowcompiles one SDK source definition and, when publishing is requested, sends its exact executable projection (steps, triggers, and bounded defaults) through the governed one-shot authoring spine. It never turns the definition back into prose for a second compile. The SDK hashes that projection and reports server verification/normalization separately; richer source metadata stays in the returned client artifact and is not claimed as persisted by the current server schema.get_workflow_trigger_catalogandauthor_workflow_triggerexpose the principal-scoped schedule/event trigger allow-list and governed trigger authoring endpoint. MCP trigger authoring is staging-only and cannot activate a trigger; activation belongs to an explicit human-controlled SDK/product surface. Direct SDK trigger authoring also defaults to disabled. Unknown filters and implicit schedules fail closed.- Convenience wrappers include
business_create_invoice,business_write_email,business_draft_contract,business_review_contract, andbusiness_schedule_meeting.
Primitives are more than raw connector calls. Each primitive includes setup
requirements, trigger events, emitted events, follow-up primitives, and builder
guidance, plus a lightbulb.primitive_runtime_contract.v1 runtime contract.
Workflow composition carries lightbulb.workflow_compiler_contract.v1 so Agent
Builder can sequence primitives, add hidden setup, and preserve approval,
observability, retry, and recovery behavior. For example, the email primitive
tells Agent Builder to include reply webhooks or polling watchers, thread
context capture, reply classification, and follow-up branches so the user does
not need to know what a webhook is.
The backend ownership model is: Backbone plans and reasons across primitives;
Agent Builder compiles workflow or loop definitions; installed typed SDK
implementations execute provider-free previews; AutoCompany/workflow runtime
runs repeatable loops; Coding Agent is used only for implementation gaps such
as new adapters, new primitives, or approved code-delivery packets. Backbone's
action=execute route never treats preview_only as advisory: reply
classification, email, invoice, and meeting steps are Pydantic-validated and
run with the in-memory connector preview runtime. Consequential catalog entries
without a typed implementation (currently contract drafting and employee
onboarding) fail closed instead of delegating to an LLM or domain route. An
approved external write must use the separately governed hosted connector
runtime.
The same SDK-first authoring loop is available directly in Python:
from datetime import timedelta
from lightbulb import (
compile_business_workflow_definition,
simulate_business_workflow,
validate_business_workflow_definition,
)
workflow = compile_business_workflow_definition(
"Email overdue customers and schedule meetings when they reply",
primitive_ids=["communication.write_email", "calendar.schedule_meeting"],
trigger_event="invoice.overdue",
owner_role="finance_manager",
inputs={
"attendees": ["customer@example.com"],
"title": "Invoice follow-up",
},
loop=True,
max_iterations=5,
)
assert validate_business_workflow_definition(workflow)["valid"]
dry_run = simulate_business_workflow(
workflow,
approvals={
"communication.write_email": True,
"calendar.schedule_meeting": True,
},
)
assert dry_run["status"] == "completed"
assert dry_run["side_effects"] == "none_simulation_only"
# A false publish flag is a zero-write local draft. Publishing sends this
# validated definition projection through the governed user-plane endpoint (JWT) or
# internal service-plane endpoint (ApiKeyAuth); the server is still the
# validation gate of record and only publishes a valid version.
artifact = client.author_agentic_workflow(
workflow["objective"],
definition=workflow,
publish=True,
)
assert artifact["authoring"]["definitionRecompiled"] is False
trigger = client.author_workflow_trigger(
artifact["workflowDefinitionId"],
trigger_type="event",
event_type="email.received",
enabled=False, # stage first; activate only after explicit user confirmation
)
The inputs argument declares additional runtime input keys only. Its values
are deliberately not copied into the persisted workflow DSL, so customer data
and credentials cannot be multiplied across versioned step configuration.
Supply actual values when starting a workflow instance; connector credentials
must come from Lightbulb's scoped connector vault, never workflow inputs.
loop=True emits a persisted lightbulb.bounded_workflow_loop.v1 contract.
The final action has one exact back edge guarded by
$.payload.outputs.continue_loop == true and an unconditional terminal edge.
The compiler limits the graph to len(steps) * max_iterations <= 100; Spring
validates the mirrored contract and persists iteration/transition counters so
a crash or resume cannot mint a fresh budget. Local simulation is deterministic
and accepts loop_iterations=max_iterations + 1 only to demonstrate the
fail-closed exhaustion result. Authored cost and timeout values still stop the
next dispatch; hard cancellation of an already-running provider call remains a
separate watchdog concern.
New catalog entries belong in lightbulb.business_primitives. Executable
implementations belong behind BusinessProcessPrimitive with Pydantic models
and runtime tests. MCP consumes those SDK modules; it is not a second primitive
implementation registry.
Executable primitives and custom projects
Version 0.14 adds actual business process implementation code rather than only primitive metadata and Backbone prompts:
ConnectorExecutionRequest/ConnectorExecutionResultnormalize Tool invocation, errors, approval state, preview behavior, and idempotency.HostedConnectorExecutoruses the authenticated Lightbulb control plane for reads, safe previews, and the staged governed-write contract. The ordinary project API at/api/tools/governed-invokeremains on an explicit production rollout hold: it requires bothGOVERNED_CONNECTOR_EFFECT_BOUNDARY_ENFORCED=trueandGOVERNED_CONNECTOR_EXECUTION_ENABLED=true, and otherwise fails before dispatch. The verified-envelope hosted-worker lane is a distinct endpoint,/api/internal/tools/governed-invoke, with its ownGOVERNED_CONNECTOR_WORKER_ENABLEDgate plus exact write/read Tool allowlists and pinned catalog versions. Enabling one lane never enables or certifies the other. In either lane Spring binds dispatch to the exact project account, tenant binding, native adapter/handler, target digest, request, and governed journal/provenance contract.InMemoryConnectorExecutorprovides deterministic project tests and local-only idempotent simulation.BusinessProcessPrimitiveandbusiness_process_primitiveprovide typed, versioned implementation contracts that custom projects can extend.LightbulbProjectdeclares allowed primitives, allowed connector Tools, secret references, policy, and event-routed workflows.ProjectRuntimeresolves deterministic input bindings, routes structured events, bounds loops, preserves exact project-bound connector account aliases, and pauses on approval, missing input, or policy blocks.DurableProjectRuntimeadds revisioned pause/resume, schedules, idempotent event ingestion, expiring worker leases, and crash-safe custody of opaque connector account aliases. Hosted projects persist this state under authenticated tenant/company/project scope.RuntimeOutcomerecorders automatically capture sanitized status, latency, approval state, and failure kind without retaining inputs or outputs.- Connector conformance covers every provider Tool declared by the shipped executable primitives and can compare those contracts with the live hosted Tool schemas. Production certification additionally requires provider readback, replay/conflict, error, and ambiguous-recovery attestations.
- The initial twelve-tool finance production-conformance packet is explicitly
write-only. It does not certify the governed
quickbooks.list_accountsorquickbooks.get_journal_entryREAD; each Tool requires its own schema/effect, exact route/account isolation, READ-provenance, output-commitment, and normalized-error evidence without a fabricated approval or write attestation.
The SDK ships executable primitive implementations across communication,
finance, calendar, legal, CRM, people, documents, approvals, project delivery,
GTM, learning, physical operations, and regulated controls.
Writes are preview-only by default. In-memory connector writes require an
approval reference and all write requests require derived idempotency keys.
Hosted writes additionally require a platform Project UUID. An apply call with
no approval reference returns pending_approval plus the opaque ApprovalTask
UUID created by Spring. After a human approves it through the normal approvals
surface, retry the same run/request with that reference; Spring accepts it once
only when Tool, canonical inputs, idempotency identity, scope, and actor match.
Caller-declared effects are drift assertions only; uncatalogued or mismatched
Tools fail closed. project_ref is correlation metadata only and can never
substitute for the authenticated, company-bound Project UUID.
The major operating-domain additions are typed, deterministic control
evaluators and bounded lifecycle projections over normalized snapshots. They do
not pretend to be an ERP, WMS, MES, HCM, PLM, or GRC system of record. A
ready, candidate_validated, or locally advanced result is evidence that the
supplied package passed the declared SDK policy; it is never posting,
fulfillment, employment, safety, regulatory, or deployment authority.
| Operating area | Executable SDK surface | Covered control package | Authority boundary |
|---|---|---|---|
| Finance and accounting | finance.discover_ledger_accounts, finance.evaluate_journal_entry_controls, finance.prepare_journal_entry, finance.post_journal_entry, finance.reconcile_journal_post, finance.evaluate_period_close_readiness, finance.evaluate_operating_subledger_controls, finance.propose_period_close_transition |
Governed chart-of-accounts discovery; content-bound QuickBooks/Xero journal preparation, approval-gated posting and independently evidenced readback; operating controls plus a bounded trial-balance → reconciliation → adjustment → subledger-lock → elimination/consolidation → approval → close proposal lifecycle | Spring owns authenticated scope, connector-account custody, RBAC, approvals, the governed execution journal, ledger/subledger writes, close, persistence, recovery settlement and audit. Ambiguous journal or close effects never auto-retry. |
| Procure-to-pay | procurement.propose_vendor_onboarding_transition, procurement.evaluate_purchase_to_pay_controls, procurement.propose_procure_to_pay_transition |
An exact-scope identity → due-diligence → qualification → approval → bank-control → setup-readiness → activation-candidate vendor lifecycle, plus a revision-, evidence- and idempotency-bound requisition → approval → PO → receiving → three-way match → exception/closure proposal lifecycle | The SDK produces validated candidates/proposals only; Spring owns private-artifact checks, KYC/AML and sanctions facts, approval custody, bank-data verification, durable idempotency, vendor-master and procurement persistence, provider writes, monitoring and audit. Caller-authored authority evidence cannot activate a vendor or produce an authoritative applied result. |
| Supply chain | supply_chain.evaluate_plan_fulfillment_controls, supply_chain.propose_execution_transition |
Supplier performance/risk controls plus a bounded demand forecast → S&OP → MRP → allocation → replenishment → warehouse release → shipment/custody → delivery or exception-resolution → closure candidate lifecycle | No optimizer, ERP, WMS, TMS, carrier, customs, custody, delivery or inventory authority is granted; Spring and source systems retain approvals, facts, persistence and audit. |
| Manufacturing and field quality | operations.verify_bom_inventory_traceability, manufacturing.advance_execution_lifecycle, manufacturing.evaluate_ehs_recall_field_quality_controls, maintenance.propose_work_order_transition |
Exact-scope released BOM/routing evidence; scheduled production orders; ordered shop-floor completion; UOM-safe lot/serial genealogy; full-scrap closure; quality holds; nonconformance/CAPA/concession evidence; EHS, recall and field-quality controls; and a bounded request → plan → authorization/schedule → execution → independent inspection → return-to-service → close candidate maintenance lifecycle with LOTO, parts, tools, labor and custody checks | Lifecycle output is an immutable SDK projection. Spring must authenticate roles and approvals and owns MES/QMS/EAM/CMMS/ERP persistence, permits and LOTO facts, labor and inventory effects, product release, quarantine, reporting, recall, maintenance dispatch, return to service and closure. |
| Commercial operations | commercial.evaluate_quote_order_contract_controls, commercial.propose_operations_transition |
A bounded CPQ/quote → contract/order review → subscription/entitlement → billing-model-specific flat, seat, usage, or hybrid proposal → renewal → channel attribution → commission/RevOps handoff lifecycle | The SDK materializes only a candidate projection. Cadence proration, tiering, credits, tax, invoice materialization, pricing, booking, contracting, billing, entitlement, channel and commission writes remain governed Spring/hosted operations. |
| Customer service | service.intake_and_classify_case, service.route_and_escalate_case, service.submit_resolution_for_verification, service.verify_case_resolution, service.propose_remedy_authorization, service.evaluate_case_resolution_controls, service.propose_asset_remedy_transition |
Evidence-custodied intake/classification, deterministic SLA clocks, escalation floors, resolution/customer verification, and risk/SoD-bound refund, credit and RMA proposals; plus bounded warranty-entitlement → depot-custody or field-plan → diagnosis → work preparation/completion → independent verification → return/reinstallation → customer verification → closure-candidate repair or replacement lifecycles | Standalone mode only validates read-only candidates. Spring owns authentication, RBAC, approval, persistence and audit; governed case, warranty, depot, field-service, inventory and carrier systems own every refund, credit, return, repair, replacement, dispatch, custody, case mutation and customer-outcome effect. |
| People operations | people.evaluate_worker_lifecycle_controls, people.propose_operations_transition |
A bounded recruiting/candidate → worker activation → shift/time/leave → performance/compensation → learning/certification → payroll-handoff → offboarding/access-revocation candidate lifecycle with exact pay-period and evidence lineage, including deterministic full-period annual-salary handoff | The SDK produces a content-bound candidate only. Salary proration, overtime, adjustments, deductions, tax, net pay, HCM/payroll/IAM writes, employment decisions, approvals, persistence, provider effects and audit remain Spring/host-authoritative. |
| Product and engineering | product.evaluate_release_governance_controls, product_engineering.propose_lifecycle_transition |
A bounded requirements → roadmap/release target → specification/BOM baseline → independent design review → engineering change → V&V → release candidate → telemetry → vulnerability/defect disposition lifecycle with exact genealogy | The SDK cannot approve a change, release a product, accept risk or close a defect; PLM/ALM writes, approval, persistence and audit remain hosted-system responsibilities. |
| Compliance and regulated operations | compliance.evaluate_regulated_controls, compliance.propose_regulated_operations_transition |
Seven exact-scope independent case tracks for policy/control/assessment, incident/breach, KYC/AML, applicable-domain regulated quality, export control, retention with conditional legal hold, and model risk. Only the policy track is an ordered establish → test → assess chain; unrelated regulated cases are never forced into fictional predecessor relationships. | Legal/regulatory determinations, filings, holds, account decisions, approvals, persistence and audit stay outside the SDK. |
| Omnichannel communication | communication.resolve_cross_channel_identity, communication.evaluate_jurisdiction_channel_policy, communication.plan_governed_voice_call, communication.normalize_provider_outcome, observe_whatsapp_delivery |
Cross-channel identity, jurisdiction/channel consent and suppression, governed SMS/WhatsApp materialization, voice planning, signed Spring-custodied WhatsApp webhook observation, and normalized delivery/outcome states | Spring signs short-lived policy decisions and owns sender/account custody, routes, writes, webhook signature verification, private payload retention, durable replay protection and authenticated observations; provider acceptance is never promoted to delivery or business outcome. |
| Production closure | operations.evaluate_production_connector_conformance, operations.evaluate_production_connector_read_conformance, operations.evaluate_production_execution_readiness |
Exact route/schema/journal/provider readback/replay/conflict/error/recovery evidence, hosted writes, governed reads, bounded loops, transactional workflow/HITL publication recovery, transport recovery, SLO/replay/incident evidence and measured business outcomes | All only propose exact per-Tool certification candidates that retain the complete bounded proof; production and deployment authorization remain false. A write packet cannot satisfy an exact required-Tool gate for quickbooks.list_accounts or quickbooks.get_journal_entry. |
This change set does not provide live provider-conformance attestations,
qualifying SLO or business-outcome measurements, or operator certification. SMS,
voice, and WhatsApp transport recovery and the production-disabled worker-side
subagent STEP_REQUESTS producer paths also remain uncertified; company-running
readiness is false.
Every result is content-bound by deterministic operation/evidence digests and
the executable runtime emits versioned receipts. The production evidence and
incident contract is in
docs/lightbulb-sdk-production-execution-runbook.md.
The canonical governed voice Tools are twilio.place_call_turn and
twilio.lookup_call_status. The SDK materializer/observer keeps the raw call
SID in private dispatch custody and exposes only an HMAC-bound public receipt.
The Spring SMS/voice routes remain dark unless operators install both a reviewed
Twilio HTTP transport and a production vault resolver; neither implementation is
included here, and a catalog row or test fake is not transport certification.
WhatsApp has SDK policy/materialization contracts plus a zero-write observer for
short-lived, HMAC-sealed Spring webhook artifacts. It still has no native Spring
adapter, Meta signature-verification endpoint, provider HTTP transport, or
durable replay journal. Crash-safe private provider-ID recovery is therefore
uncertified for SMS, voice, and WhatsApp, and ambiguous provider acceptance is
never auto-replayed.
The encrypted workflow publication outbox protects orchestrator-owned requests
and 13 of the 15 audited Spring direct STEP_REQUESTS lanes, including
integration, internal-tool, legal, voice/receptionist, explicitly authorized
scheduled-finance and CRM, and feedback dispatch. Commerce-intelligence and
finance-market-data schedules remain deliberately undispatched because their
profiles do not identify an authorized actor or service principal; they never
substitute an arbitrary enabled user. The direct registrar joins an existing
business transaction when present, persists an exact-scope running workflow
receipt and outbox row, and leaves Kafka publication to the fenced relay.
Immediately before Kafka publication, the relay locks and rechecks the workflow,
exact step generation, selected agent, and current actor authority.
Definition-backed envelopes must match a fresh full-RBAC snapshot. Direct
AppUser envelopes remain canonical identity-only claims (roles=[],
permissions_scope=[], and no component claims); the relay verifies current
identity and tenant/company scope without copying RBAC into the model-visible
envelope. The exact external receptionist exception remains limited to sole role
EXTERNAL_CONTACT and receives no runtime-authority token.
For every authoritative signature-v3 step, the worker repeats
POST /api/internal/workflows/instances/{traceId}/state-preflight after context
hydration and immediately before executor.dispatch, sending only a digest of
the signed actor claims. Spring derives full-RBAC, identity-only, or external
authority from the locked Workflow Instance. A deterministic mismatch
terminalizes workflow/control and skips execution; a Spring or RBAC-store outage
leaves the Kafka record uncommitted for retry.
HITL_REQUESTS and HITL_DECISIONS now use the same encrypted transactional
outbox, binding the waiting Workflow Instance and terminal ApprovalTask update
to the exact resume generation. Authoritative Spring lifecycle facts on
agent.workflow.lifecycle.v1 and workflow-owned DLQ facts on
agent.workflow.dlq.v1 use the separate encrypted V1865 transactional outbox.
The legacy source topic agent.workflow.events remains non-authoritative and
best-effort: V1867 makes an accepted record durably replayable, but cannot make
its source publication transactional or crash-safe. V1866 initializes the
generation authority in LEGACY_DIRECT so mixed-version rolling releases keep
one writer. The release controller transitions that authority to OUTBOX only
after the live Spring replica carries the exact
v1865-workflow-event-publication-v1 generation and the active V1865 queue is
empty. In OUTBOX, the canonical orchestrator transaction persists the
encrypted lifecycle or DLQ fact and the relay waits for a complete broker
acknowledgement. Stable event id and publication order headers are inputs to
the database materializer, which suppresses duplicates and assigns cursor
order. A PARKED head retains ciphertext and active capacity until an
authenticated, exact-scope operator commits append-only RETRY or
ABANDON_TAIL evidence through the resolution controller. PARKED is
exclusively a pre-publish poison or integrity failure, and operator RETRY is
only for poison that was repaired before another publish attempt. Broker
failure, timeout, or ACK-metadata uncertainty remains PENDING for stable
automatic retry and never becomes PARKED.
Before any local SSE fan-out, V1867 durably materializes the security-sanitized canonical event in PostgreSQL under the exact tenant/company/trace scope. Using a stable event id when present and broker coordinates for pre-header records, the database materializer suppresses duplicate acceptances and assigns per-scope cursor order; any identity, semantic, coordinate, or scope conflict fails closed. The independent materialization transaction commits the canonical row, broker observation, and cursor before fan-out or Kafka offset advancement. If the JVM fails after that commit, the retried Kafka record resolves to the same row and cursor and safely retries delivery instead of creating a second event. Strict, lossless JSON parsing preserves exact decimal and integer values from Kafka through PostgreSQL replay.
Authorized SSE reconnects pass Last-Event-ID into a bounded,
repeatable-read PostgreSQL snapshot/replay and receive rows in cursor order
through one captured high-water mark before joining live delivery. Live
delivery uses bounded async fan-out and bounded per-scope, per-tenant, and
global subscriptions; saturation closes the affected streams so clients
recover through durable replay. SSE frames carry the stable event id. The
per-JVM broadcast consumer starts an ephemeral group at earliest, uses a
bounded poll interval with a pausing backoff handler, and consumes the canonical
lifecycle topic's 35-day window so a restarted replica can rematerialize
retained records idempotently.
V1867 scrubs canonical event content after 15 minutes while retaining bounded
identity, scope, cursor, and hash metadata for exactly 35 days.
The database duplicate-suppression and replay evidence is therefore bounded to
exactly 35 days. Global and per-tenant row/byte reservations fail closed,
scheduled scrub/purge work is batch-bounded, and event metadata purges
unconditionally at that exact boundary. Only independent cursor retirement is
fenced by nonterminal or recent workflow state and active or parked outbox
references. A content-free health indicator reports capacity consistency,
exhaustion, scrub lag, purge lag, and reconciliation age from bounded summaries
plus scheduled exact reconciliation. This closes the bounded COMPLETE_SLICE5
durable materialization contract; it does not change the released authority's
production-dark DARK_BASELINE/DISABLED posture.
V1865/V1866 objects are owned by the governed-writer database role. The
existing Spring datasource login must be the exact project401_runtime member,
while Flyway and release transition use a distinct migrator login. The Spring
runtime database credential must be exclusive to Spring; activation fails
closed if the rendered Compose topology shares it with another service.
Runtime receives only the pinned SECURITY DEFINER authority row-lock/read
function and cannot read or mutate the backing authority/audit tables directly.
The two Python worker-side subagent-spawn/resume producers are outside Spring
authority and are fixed off in production with SUBAGENT_SPAWN_ENABLED=false;
enabling them is unsupported until they gain Spring-owned signing, generation,
and durable publication. This SDK evaluation never upgrades those remaining
boundaries to production certification. The reserved automatic-trigger lane is admitted only
from a consumed durable WorkflowTrigger receipt and is revalidated against its
exact definition, scope, and current role or creator access. The bounded public
Client Page lane is limited to receptionist_booking and call_center_routing;
Spring derives it from one enabled page configuration, a published definition,
and current CLIENT component access, then persists and revalidates a versioned
receipt at relay and worker preflight. That public lane receives no connector
runtime-authority token. Every other generic public/synthetic or unmarked
principal lacks a reviewed persisted contract and fails closed before Kafka.
Any stale or legacy worker delivery is rejected by the execution preflight;
never substitute an arbitrary enabled user.
Hosted workers must derive both client authentication and execution identity from the same verified project envelope. Caller-supplied tenant, company, project, approval, or connector-account claims are rejected as authority:
from lightbulb import HostedConnectorExecutor, LightbulbClient
worker_client = LightbulbClient.from_verified_envelope(
"https://agents.lightbulbpartners.com",
verified_project_envelope,
)
executor = HostedConnectorExecutor.from_verified_envelope(
worker_client,
verified_project_envelope,
)
result = executor.execute(request)
The server verifies the envelope again, resolves the exact cataloged Tool and
account alias, consumes any approval, and journals the effect. An ambiguous
provider result becomes in_doubt: recovery/readback must prove the outcome
and Spring must settle the governed journal before any retry. The generic
durable SDK runtime never accepts caller-authored recovery attestations or
replays an unresolved external operation, so a timeout cannot become a
duplicate financial effect.
from lightbulb import (
InMemoryConnectorExecutor,
LightbulbProject,
ProjectRuntime,
default_primitive_registry,
)
project = LightbulbProject.model_validate({
"project_ref": "reply-router",
"name": "Reply router",
"primitive_refs": [
"communication.classify_reply",
"calendar.schedule_meeting",
],
"workflows": [{
"key": "route_reply",
"title": "Route reply",
"entry_step": "classify",
"steps": [
{
"id": "classify",
"primitive_ref": "communication.classify_reply",
"input_mapping": {"reply_text": "$input.reply_text"},
"routes": {"meeting.requested": "schedule"},
},
{
"id": "schedule",
"primitive_ref": "calendar.schedule_meeting",
"input_mapping": {
"attendees": "$input.attendees",
"title": "$input.title",
},
},
],
}],
})
runtime = ProjectRuntime(
project,
default_primitive_registry(),
InMemoryConnectorExecutor(),
)
run = runtime.run_workflow(
"route_reply",
{
"reply_text": "Can we schedule a call next week?",
"attendees": ["buyer@example.test"],
"title": "Renewal follow-up",
},
)
assert run.status == "completed"
For durable execution, wrap the same validated runtime and resume the exact paused step after approval or missing input is supplied:
durable = runtime.durable()
pending = durable.start_workflow(
"choose_window",
inputs,
preview_only=False,
run_ref="launch-42",
)
completed = durable.resume_workflow(
"launch-42",
input_updates={"decision": "August 15"},
approval_refs={"approval.request_decision": "approval-123"},
)
LightbulbClient.build_durable_project_runtime(project) uses the hosted
checkpoint ledger when hosted_project_id is set and an atomic local JSON store
otherwise. Use schedule_workflow, ingest_event, and run_next for timers,
idempotent event dispatch, and distributed worker claims. Durable retry is
opt-in (policy.retry_policy.max_attempts defaults to 1): retryable failures
are revision-saved before invocation, scheduled with capped exponential
backoff, and keep stable per-step-visit connector identities. Approval and
missing-input resumptions do not consume retry attempts. While a synchronous
primitive is active, the runtime renews its lease at a bounded cadence with an
owner/revision fence. Hosted claims and renewals use the control-plane clock;
lost ownership or renewal failures are surfaced before any stale completion
can be persisted.
See CUSTOM_PROJECTS.md for hosted execution, custom primitive authoring, connector fakes, approval retries, input bindings, MCP tools, status semantics, and the current runtime limits.
Continuous workflow improvement
Version 0.14 combines the local supervisor with the durable, authenticated control plane and executable SDK catalog. The supervisor scores every catalog contract and every shipped implementation, measures executable coverage, records trend history, merges a deduplicated improvement queue, and prepares one SDK-first work packet for the coding harness:
# One evaluation cycle
lightbulb improve-workflows run --output-dir .lightbulb/workflow-improvement
# Finite supervisor; create .lightbulb/workflow-improvement/STOP to stop earlier
lightbulb improve-workflows watch \
--output-dir .lightbulb/workflow-improvement \
--interval-seconds 900 \
--max-iterations 96 \
--max-elapsed-seconds 86400 \
--max-no-progress-runs 2 \
--sync-server
lightbulb improve-workflows status --output-dir .lightbulb/workflow-improvement
lightbulb improve-workflows queue --output-dir .lightbulb/workflow-improvement
# Persist the latest run and packets under authenticated tenant/company scope
lightbulb improve-workflows sync --output-dir .lightbulb/workflow-improvement
lightbulb improve-workflows server-status
lightbulb improve-workflows server-queue
Each cycle writes latest.json, state.json, bounded history.jsonl, and
improvement-queue.json; history-compaction.json accounts for retired rows by
count, source bytes, and rolling digest, while next-work-packet.json exists
only while actionable work is queued. The watcher has no unbounded mode:
omitted SDK limits use 96 cycles, 24 hours, and two stable no-progress runs,
with lower storage/intake caps and non-overridable hard ceilings. Its final
supervisor-stop.json receipt records the exact stop reason and budget.
Primitive execution records runtime outcomes automatically, and
LightbulbClient.run_workflow_improvement_cycle() consumes the queued
observations by default. Manual --observed-outcomes outcomes.json remains
available with a 1 MiB file limit. Each evaluator cycle inspects at most 256
rows by default. Only allow-listed status, error-kind, latency, validation,
approval, timestamp, primitive, and harness fields are retained; malformed or
overflowing input produces a blocking finding instead of being silently
coerced or ignored.
The evaluator is deliberately proposal-only. It never edits code, invokes an
agent or connector, publishes, deploys, or performs an external write. The
server derives tenant, company, and actor scope from authentication, stores only
allow-listed outcomes, and records one immutable hash-chained decision per
implementation, publish, or deploy scope.
After explicit implementation approval, delivery can run on the server-issued
codex/ branch through the workflow_authoring Harness contract:
lightbulb improve-workflows decide <packet-id> implementation approved \
--rationale "Reviewed tests and SDK contract"
lightbulb improve-workflows deliver <packet-id> \
--environment disposable-staging-123 --repository-ref github.com/acme/repo
lightbulb improve-workflows delivery-event <delivery-id> branch_created \
--evidence '{"branch_name":"codex/workflow-improvement-example"}'
lightbulb improve-workflows audit <packet-id>
lightbulb improve-workflows delivery-status <delivery-id>
The delivery state machine enforces isolated branch, passing acceptance checks, draft PR, CI, disposable staging, bounded canary, metric comparison, rollback on regression, and cleanup in order. It cannot deploy production. Publish and deploy each require separate immutable decisions after a passing staging canary; deploy approval additionally requires publish approval. Contract and executable implementation regressions outrank implementation gaps. Existing catalog primitives without Python implementation code are completed before the loop proposes a new catalog capability. The current 13/13 catalog is green and emits no speculative work packet until contract checks or real outcomes identify a gap.
A staging-validated improvement can now become a content-free learning
nomination without gaining training authority. Harness implementations may
return a bounded lightbulb.workflow_learning_candidate_manifest.v1; Harness
stores only its SHA-256, candidate kind, and Git commit in the immutable
IMPLEMENTATION_COMPLETED audit event. The sync/async SDK method
prepare_workflow_learning_handoff(...) then reads the exact scoped packet,
delivery, complete hash-linked audit trail, and installed-action readiness. The
MCP equivalent is prepare_workflow_learning_handoff.
The legacy lightbulb.workflow_learning_handoff.v1 remains a content-free
nomination. When the trusted custody workload is provisioned, omit
episode_manifest (or supply the SDK-derived
lightbulb.workflow_learning_episode_manifest.v2) to perform one explicit
read-only custody verification. The SDK then derives the only accepted v2
episode manifest from the authenticated snapshot dataset digest, counts, cost,
lifetime, receipt, and bundle and emits
lightbulb.workflow_learning_handoff.v2. Only the episode-input, artifact-
storage, and input-attestation blockers are resolved.
When Harness has a producer signing key, the same implementation event also
contains an Ed25519 attestation over the exact candidate artifact digest and a
scope hash covering packet, delivery, candidate-manifest digest, artifact
contract, and repository commit. The SDK notices signed evidence and performs
one additional authenticated read. Spring revalidates the signature against its
current public rotation registry, recomputes the scope from the immutable audit
event, and returns only a content-free verification summary. The SDK reconciles
that summary byte-for-byte with the caller's candidate manifest and emits
lightbulb.workflow_learning_handoff.v3; missing, expired, revoked, tampered,
or cross-scoped evidence remains v1/v2 with
candidate_artifact_attestation_required.
All three versions deliberately remain status=blocked: raw artifacts and
episodes are excluded, every funding, artifact-write, scheduling, training,
evaluation, promotion, and serving flag is false, and approved
success-contract selection, least-cost campaign admission, and every later
authority stay separate server-side operations. The candidate verification
read itself cannot admit or execute a campaign.
LIGHTBULB_WORKFLOW_CANDIDATE_SIGNING_REQUIRED and
LIGHTBULB_WORKFLOW_CANDIDATE_ATTESTATION_REQUIRED are independently
default-off in the development compose path and set to true in the production
template. The producer uses the existing Agent Workers artifact-signing key;
Spring receives only the corresponding public rotation registry. If either side
is unavailable, the nomination remains inspectable and blocked instead of
falling back to an unsigned caller claim.
Runtime setup is exposed as backend account configuration, not UI components:
list_agent_runtime_optionsget_agent_runtime_configconfigure_coding_agent_runtimeconfigure_backbone_agent_surfacetest_agent_runtime_configstart_codex_account_linkget_codex_account_link_statuscancel_codex_account_link
Use these from Codex, Claude Code, or ChatGPT-style MCP hosts when the user wants Codex or Claude Code to be their Lightbulb coding agent, or ChatGPT MCP to be their Backbone host surface.
When targeting Codex, lightbulb setup --target codex also installs the local
Codex plugin surface. It writes:
~/.codex/config.tomlwith thelightbulbMCP server.~/.codex/plugins/lightbulb-partners/with the bundled plugin manifest, MCP config, and Lightbulb skill.~/.agents/plugins/marketplace.jsonwith aLightbulb Partners Localmarketplace entry pointing at./.codex/plugins/lightbulb-partners.
Restart Codex after setup, open Plugins, choose Lightbulb Partners Local, and
install or enable Lightbulb Partners if it is not already enabled. The plugin
skill teaches Codex to use start_consulting_project_workflow for project,
custom-agent, SOP, modernization, repo, and code-delivery requests before any
domain-agent execution or GitHub writes.
Project and consulting workflow starts
Project creation has a local World Ready inspection followed by a strict two-step review/create front door plus a separate explicit feedback tool in both the compact Backbone MCP profile and the sync/async Python clients:
For an existing project, get_project_game_snapshot(project_id) fetches the
server-owned lightbulb.project_game_snapshot.v1 protocol shared with human and
agent workers. It binds the authenticated tenant, selected company, and exact
project UUID to the public JWT route or the separately guarded internal API-key
route. The SDK validates the schema, bounded finite JSON, canonical resource
paths, evidence counts, truth boundary, and locked human-gated authority before
returning it. Caller-supplied project or plan JSON can never become canonical
score, scope, evidence, or authority.
inspect_project_game_campaign remains available in the pure Python client as
an explicitly offline, unverified preview over an observed project, plan, and
optional business-cockpit payload. MCP does not expose that local-input path;
its compatibility alias accepts only a project UUID and performs the same
server fetch as get_project_game_snapshot. The local preview's ten phases
route to the real AutoResearch, Search, data-engineering,
AutoML, model-serving, Solver/AOC, approval, action, outcome, and improvement
tools. Its derived lightbulb.project_mission_briefing.v1 turns the current
mission into one fresh human/agent handoff: why it matters, what counts as done,
lead specialist, observed context, exact capability route, next no-skill/
single-skill/combination trial, expected receipt, and the selected play-style
posture. Opening or inspecting the briefing does not activate preparation,
schedule a shadow quest, dispatch a worker, call a tool, or authorize a live
action. Its sibling lightbulb.project_game_checkpoint.v1 is the truthful
results/save screen: it summarizes verified science receipts, shadow strategy
evidence, reported skill-arm observations, and real business-score
observations, then routes the next quest. It remains a project checkpoint and
never infers a mission win, causal result, admitted lesson, or agent level-up.
When an exact current Mission Run, later action binding, and linked outcome
receipt are all present, the campaign separately derives
lightbulb.project_mission_debrief.v1. That debrief reports only that evidence
returned; it still does not infer completion, victory, causal effect, learning,
or new authority. The nested
lightbulb.skill_tournament.v1 counts only explicitly labeled
shadow evidence for no_skill, single_skill, and skill_combination; it does
not verify comparability or outcome authenticity, select a winner, or authorize
promotion. It points every arm at the preferred
automl_run_skill_tournament worker tool and retains
automl_evaluate_skill_tournament for already-captured observations. The
preferred tool derives tenant/company/user/project scope and RBAC from the
parent AgentContextEnvelope, checks the task and provider budget, validates
producer signing before provider work, and owns the exact no-skill, one-skill,
and incremental-combination matrix. It runs Claude domain episodes through the
provider-only shadow lane, signs the capture once, submits it once to Artifact
Service, and returns an authenticated scoreboard plus a non-production skill
recommendation. Agents must not fabricate arm observations.
The signed lightbulb.skill_tournament_shadow_capture_bundle.v1 carries an
exact lightbulb.skill_tournament_runtime_contract.v1. Every episode must
prove complete provider/tool/mutation interception for coverage ID
lightbulb.claude-domain-tournament-provider-only.v1, at least one provider
call, no tool or mutation path, and no coverage violation. Artifact Service
independently verifies that contract along with the producer's Ed25519 key,
scope, digests, task matrix, skill pins, zero tool/write counters, and embedded
evaluator request. This authenticates the Lightbulb producer and its audited
domain-worker lane; it does not authenticate business outcomes, independently
attest the execution environment, select a production winner, promote a skill,
or authorize an action.
The orchestrator is code-available but deployment-configuration-gated. Agent
workers require either LIGHTBULB_ARTIFACT_SIGNING_KEY_FILE or the paired
LIGHTBULB_ARTIFACT_SIGNING_KEY_ID and
LIGHTBULB_ARTIFACT_SIGNING_PRIVATE_KEY_PKCS8_BASE64; Artifact Service must
trust the matching public key. Equivalent Coding, Backbone, Codex, Cursor, and
direct-connector runtime coverage is still required. Project-level offline
policy evaluation now has a separate Strategy Lab contract described below;
it verifies assignment/action/outcome receipt pairing but does not extend the
skill-tournament runtime-coverage claim, independently verify an external data
source, or prove causality.
Mission Runs add the durable save-before-action chain shared by the human campaign, sync/async clients, compact Backbone MCP, and project-scoped workers:
list_project_mission_runs(project_id)reads the exact-projectlightbulb.project_mission_run_ledger.v1.start_project_mission_run(...)requiresconfirm_start=Trueand locks the exact currentlightbulb.project_mission_briefing.v1, play style, shadow skill arm and pins, context references, run UUID, and idempotency boundary before any separately authorized action. It does not open a runtime, dispatch a worker, call a provider/tool, approve an action, or perform a write outside the Mission Run ledger.bind_project_mission_action(...)requiresconfirm_bind=Trueand binds only a later durable action event in the same tenant/company/project scope. It rejects mission bookkeeping and outcome events as action sources. The resultinglightbulb.project_mission_action_receipt.v1verifies scope and chronology only, not action semantics or external effect.- A later Project Outcome receipt may cite both the Mission Run receipt and Mission Action receipt. Only that exact chain can produce the derived Mission Debrief, and even then currentness, mission completion, causality, learning, promotion, dispatch, and action authority remain false.
The Project Training Arena preserves what the skill tournament actually tested before anyone proposes learning:
- Sync and async clients plus MCP expose
list_project_skill_matches(project_id, limit), which reads the exact-projectlightbulb.project_skill_match_ledger.v1. - Only the internal project worker has
record_project_skill_match. It derives tenant, company, user, and project fromAgentContextEnvelope, requiresautoml.experiments.execute, explicit confirmation, the exact Mission Run loadout, and the unmodified authenticated tournament orchestration receipt. There is deliberately no public or MCP record tool. - The receipt verifies a bounded provider-only capture and a common no-skill, one-skill, and skill-combination suite. The project control plane does not independently replay the Artifact Service signature, authenticate a business outcome, prove causality or skill attribution, construct a training dataset, train, update confidence/routing, promote, dispatch, act, or write production data.
- Training remains unavailable from this receipt until it is paired with an exact human-admitted Level-Up lesson and then crosses the separate governed dataset-custody and durable learning-run admission bridge.
The governed Level-Up Review is the separate human learning gate after the mission debrief:
list_project_learning_reviews(project_id)reads the exact-projectlightbulb.project_learning_review_ledger.v1.record_project_learning_review(...)requiresconfirm_record=Trueand an authenticated human. It accepts only the exact Mission Run, Mission Action, and Outcome receipt chain and the exact no-skill/single-skill/combination loadout recorded by those receipts. The human may keep it as a positive or negative shadow lesson, reject it, or defer for more evidence.- An admitted
lightbulb.project_shadow_training_observation.v1is graded future training input only. It does not prove the outside result is true, prove causality or skill attribution, mutate live skill confidence or the online learner, change routing, activate/promote policy, dispatch work, authorize an action, or write production data. - Project workers expose only
list_project_learning_reviews; they have no review-write tool and are explicitly forbidden from substituting the older live-mutatingrecord_skill_outcomepath for project mission evidence.
The Project Learning Lab joins those two independently governed proofs without pretending that packaging evidence is training:
- Sync/async clients and MCP expose
list_project_training_packs(project_id, limit). The human cockpit renders the same exact-projectlightbulb.project_training_pack_ledger.v1as a simple three-check quest: Arena match verified, human lesson admitted, and exact Mission Run plus loadout verified. - Only the internal project worker has
record_project_training_pack. It derives scope andautoml.experiments.executefromAgentContextEnvelope, requires explicit confirmation, and pairs exactly one authenticated worker-recorded Arena receipt with exactly one authenticated human-admitted Level-Up receipt. The Mission Run and no/single/combination skill loadout must match. Public SDK and MCP surfaces deliberately have no record tool. - The resulting
lightbulb.project_training_pack.v1contains one graded candidate observation, both receipt digests, bounded lineage, the Arena evidence, and a deterministic pack digest. Its adjacentlightbulb.project_learning_run_admission_plan.v1is an admission checklist, not a trainer: runtime selection, dataset custody, holdout/evaluation, budget, durable run creation, capacity, commercial reservation, operator approval, and claimability all remain false. - The next authoritative boundary is the existing Memory learning-run ledger. The candidate pack does not publish/register a dataset, select AutoML, PufferLib, or PRIME-RL, create/admit/claim/execute a run, update an online learner or routing, promote/activate a skill or policy, dispatch, act, or write production data.
The Project Training Quest carries that candidate through a fenced runtime:
list_project_learning_runs(project_id)returns the receipt-backed twelve-stage quest. Preparation creates immutable dataset custody and a durable queued Memory run; admission separately reserves exact capacity and commercial budget.- A project-scoped agent worker—not public SDK or MCP—uses
claim_project_learning_run,heartbeat_project_learning_run,checkpoint_project_learning_run, andfinish_project_learning_run. The raw Memory lease token stays inside that worker process behind an opaque handle. - Spring independently rereads Memory and appends a sanitized
lightbulb.project_learning_run_execution_receipt.v1. The shared Python and JavaScript projection rejects a wrong actor, forged authority, mismatched scope, inconsistent counts/status, or any nestedlease_token/token_hash. - A terminal
succeededreceipt completes the runtime-result stage only. It does not prove training effectiveness, complete independent evaluation, admit a learner/routing/model/policy change, promote anything, authorize an action, or prove business value. list_project_learning_result_evaluations(project_id)reads an independent replay ledger. A separate evaluator worker may complete the technical gate; an authenticated human must then separately admit or reject the exact candidate. Neither receipt changes a learner.list_project_shadow_learner_updates(project_id)is the only public SDK/MCP operation for stage 12. Apply and rollback stay worker-only, derive exact scope andlearning.runs.executefromAgentContextEnvelope, require explicit confirmation, and accept only the exact human-admittedgepa_champion_manifestchain.- The worker can change only Memory's isolated Project shadow slot and three approved paths, with a maximum revision delta of one. Exact retries are digest-bound and zero-mutation; conflicting retry IDs fail closed. Rollback is bound to the exact apply receipt and stored snapshot. The active learner, active instruction revision, routing, promotion, policy activation, dispatch, production writes, and business-effectiveness claims remain false.
project_learning_receipt_to_workflow_event(...) is the SDK bridge from a
complete raw Spring preparation, admission, or execution receipt into a
sanitized WorkflowEventEnvelope. The receipt ID becomes the deterministic
event ID, and the adapter validates the full nested project/run scope, actor
attestation, and lifecycle bindings before excluding actor, budget, provider,
worker, credential, and lease fields. A normalized
ProjectLearningRunPreparedReceipt or ProjectLearningRunAdmittedReceipt is
intentionally rejected: those freely constructible SDK projections omit the
scope and actor evidence required by this boundary. The event's source is a
receipt-contract routing label, not cryptographic proof that an arbitrary
Python object came from Spring. Preserve the authenticated Spring response
boundary, then pass the projected event to
DurableProjectRuntime.ingest_event(...); with HostedCheckpointStore, the
write also uses Spring's authenticated project-event endpoint and its
RBAC/scope checks. This is a bounded receipt projection, not a Kafka stream: it
exposes no topic, partition, offset, cursor, total ordering, complete history,
or exactly-once broker claim.
Projects now share one append-only real-score contract across the human UI, sync/async SDK clients, MCP hosts, and project-scoped agent workers:
list_project_business_outcomes(project_id)readslightbulb.project_business_outcome_ledger.v1.record_project_business_outcome(...)requiresconfirm_record=True, a selected company, an explicit baseline and observed value, and a stable observation/idempotency ID. Human calls create anactor_authenticated_attestationreceipt. A caller may instead bind an existing same-project event to receive the strongersame_scope_project_event_boundtier.- Domain workers use the identically named worker tool. Their path derives
tenant, company, user, and project from
AgentContextEnvelope, requiresautoml.experiments.execute, requires a durable same-project source event, and re-verifies the returned scope and source binding.
Both tiers classify metric movement only. They explicitly leave external source truth, causal attribution, learning admission, skill-confidence changes, policy promotion, and production action authority false. Those require separate evidence and governance steps.
The Project Science Ledger gives the campaign and every worker one durable context spine from business question to shadow policy candidate:
list_project_science_evidence(project_id)reads the exact-projectlightbulb.project_science_ledger.v1before research, data, AutoML, model-serving, solver, or control work.record_project_science_evidence(...)records one hypothesis, search, data-engineering, ML/serving, or solver/control artifact. Later stages require the exact predecessor receipt; agent workers must also bind a durable same-project source event and explicitly confirm the write.- Each receipt binds tenant, company, project, actor, artifact reference and SHA-256 identity, predecessor receipts, business metric, reported tools, and reported skills. Tool and skill lists are not runtime attestations.
- The shared Science Quest turns only scope/predecessor-verified receipts into green campaign evidence. Existing plan fields remain visible as amber claims until a receipt exists.
This ledger proves identity and lineage, not artifact contents, hypothesis validity, model quality, policy optimality, causality, learning admission, or action authority. Dataset registration, training, deployment, policy activation, and production actions continue through their existing gates.
The Project Strategy Lab connects decision-time policy logging to those real score receipts without pretending that correlation is learning:
record_project_policy_assignment(...)records 2-20 action alternatives, the chosen action, one behavior distribution, 1-8 candidate distributions, the objective metric, and the decision timestamp while the outcome is still unknown. Agent workers must bind a durable same-project decision event.- The eventual
record_project_business_outcome(...)call links the immutable assignment receipt and exact action event throughpolicy_assignment_receipt_idandaction_receipt_id. evaluate_project_offline_policy(...)accepts 20-2,000 unique assignment and outcome receipt pairs. Spring reconstructs and scope-checks every assignment, chosen action event, metric, and outcome before sending only bounded numeric episodes to Artifact Service.- Artifact Service returns deterministic IPS/SNIPS estimates, a seeded
bootstrap interval, effective sample size, support, and importance-weight
diagnostics. Passing all readiness gates creates only a
shadow_learning_candidate; it never proves the propensities or causal assumptions, admits learning, changes skill confidence, promotes/activates a policy, or authorizes an action.
Sync and async clients also expose list_project_policy_assignments(...) and
list_project_policy_evaluations(...). All writes require an explicit
confirmation flag, a selected company, and stable UUID/idempotency identity.
inspect_project_creation_world_readyevaluates locally and the Python client method makes no network call. The MCP wrapper may perform its normal authentication/account-context bootstrap on first use, but it never calls a project or preflight endpoint. It returnslightbulb.project_start_readiness.v1with bounded checks, blockers, one next action, and alightbulb.project_game_start.v1projection shared with the human New Campaign view. The projection names the reviewed win condition, one bounded play style, a planned-but-undispatched Project Agent starter, read-only first mission, and the planned data/ML/solver campaign. The three play styles areguided_human_in_the_loop(wait for each mission),proactive_copilot(propose and prepare), andautonomous_shadow(run read-only or sandbox shadow quests on a schedule). Guided is the default. A play style is an initiative preference only: runtime activation still needs separate authority, and the projection keeps dispatch, live actions, production writes, and approval authority false. Its skill trials are shadow-only (no_skill,single_skill, andskill_combination), and policy learning is explicitlynot_admitted. Participant role and experience lens are presentation/protocol choices only: the manifest never includes scope IDs, a backend grant, create authority, downstream action authority, worker dispatch authority, or model-promotion authority.preflight_project_creationsends only the normalized projectnameandinstructionsto/api/enterprise-copilot/project-preflight. The SDK forcesshadowmode, disables project/action/external writes, validates the fullproject_creation_preflight.v1event, and accepts the receipt UUID only from the separateexecutionSSE event. A selected company is required so the trusted episode receipt has one exact tenant/company namespace. When bounded public research runs, the review surfaces only exact retrieved excerpts bound to a URL in the mechanically observed public-source inventory. Model paraphrases, composite provider answers, uncited text, and invented references are omitted rather than presented as facts. Before any model-authored search reaches a public provider, its terms must match the bounded public-research vocabulary or a proper noun the user explicitly marked aspublic topic <name>(equivalent public entity labels are also accepted). Private/unknown terms and unapproved numeric identifiers are withheld; one rejected proposal does not discard a separate safe query. Current receipts also include a boundedcriticality_findingsledger. Each finding binds its plan impact, evidence references, calibrated confidence, cheapest resolution, andblock,warn,assume, orignoredisposition.critical_gaps,open_questions, andnext_questionare derived only fromblockandwarn; assumptions and already-covered facts cannot manufacture a user question. Anignoredisposition must carry a field-matched contextual draft span bound by UTF-8 byte offsets and SHA-256; the SDK revalidates it against the receipt-bound draft. Historical parser-v2 receipts remain readable, while newly produced ledger receipts are parser v3. A receipt chain permits at most four explicit user-answer refinements; a fifth is rejected by the SDK, server, and database.create_project_from_preflightaccepts the complete receipt returned by step 2 and requires literalconfirm_create=trueplus a selected company. It posts only the receipt-bound name, instructions, execution UUID, optional boundedplay_style, optional workspace/repository UUIDs, and optionalIdempotency-Keyto/api/projects. A retry cannot silently change the selected play style.submit_project_creation_preflight_feedbackaccepts that same complete receipt, the three literal valuespass,fail, ornot_assessedfor helpfulness, calibrated criticality, and factual grounding, plus a stable 8-128 character idempotency key. For MCP it also requires literalconfirm_user_feedback=true. The SDK takes the episode only from the trustedagent_episodeSSE event and sends no tenant, company, project, user, execution, reward, rubric, or training fields.
For MCP, pass preflight_project_creation's complete JSON as receipt_json to
create_project_from_preflight. Do not synthesize an execution ID, edit the embedded draft, answer the
preflight's next_question automatically, or treat preflight as permission to
create. Product Machine plans, inferred scope, and approval state are not
accepted by this create path.
Feedback is append-only and must reflect judgments the user actually supplied.
Never infer positive feedback from project creation, approval, acceptance, or
the absence of a complaint. A unanimous pass is a user preference/usefulness
signal for the governed evaluator; it is not independent factual proof or a
business-outcome claim. A 409 means the one decision already conflicts, and
a 422 can mean the neutral episode has not finished server evaluation yet;
the SDK surfaces both rather than turning either into success.
The equivalent preview Python API is:
readiness = client.inspect_project_creation_world_ready(
"Customer onboarding",
"Automate the handoff after Closed Won.",
play_style="proactive_copilot",
)
if not readiness["ready"]:
raise RuntimeError(readiness["next_action"]["label"])
print(readiness["game_start"]["win_condition"])
print(readiness["game_start"]["first_mission"])
campaign = client.inspect_project_game_campaign(
project={"id": "project-id", "name": "Customer onboarding"},
plan={"game_start": readiness["game_start"]},
business_cockpit={},
)
print(campaign["current_mission"])
print(campaign["mission_briefing"])
print(campaign["game_checkpoint"])
print(campaign["campaign_map"][0]["capability_route"])
print(campaign["skill_lab"]["tournament"])
receipt = client.preflight_project_creation(
"Customer onboarding",
"Automate the handoff after Closed Won.",
)
# Present receipt.preflight.next_question to the user when present. A separate
# explicit user decision is required before this call.
project = client.create_project_from_preflight(
receipt,
confirm_create=True,
play_style="proactive_copilot",
idempotency_key="create-customer-onboarding-v1",
)
# Canonical state comes from the authenticated server, not the local preview.
snapshot = client.get_project_game_snapshot(project["id"])
print(snapshot["campaign"]["current_phase"])
print(snapshot["wealth"])
print(snapshot["mission"])
print(snapshot["authority"])
# Only after the user explicitly judges each dimension. This call is never
# triggered by create_project_from_preflight.
feedback = client.submit_project_creation_preflight_feedback(
receipt,
helpfulness="pass",
calibrated_criticality="pass",
factual_grounding="not_assessed",
idempotency_key="customer-onboarding-review-feedback-v1",
)
ProjectCreationDraft, ProjectCreationPreflight,
ProjectCreationPreflightReceipt, ProjectCreationPreflightError,
ProjectPreflightFeedbackDimensions, and
ProjectPreflightSemanticFeedbackReceipt are public typed contracts. The
async client exposes the same network methods; await them. Its explicitly
offline inspect_project_game_campaign preview remains synchronous.
For Codex, Claude Code, Cursor, and ChatGPT connector-style hosts, route broad
project ideas through the Lightbulb backbone instead of jumping straight to code
or connector writes. Use start_consulting_project_workflow to start or
continue the consulting_project_workflow when the user wants to build an app,
automate a workflow, create a custom agent, rewrite SOPs, modernize operations,
or turn an idea into implementation work. If a host has not refreshed the latest
tool surface yet, call backbone_execute with workflow_type set to
consulting_project_workflow.
That workflow collects intake facts with provenance, validates requirements and
scope, identifies SOP impact, generates SOPs/process maps when changed or
referenced, then creates approved work packets. Code
Workspace, GitHub repository setup, draft PRs, deployments, customer messages,
and connector mutations remain behind the Product Machine approval gates. When
approved coding packets exist, the Project Product Machine plan should carry
workflow_type=consulting_project_workflow, dispatch_contract,
code_delivery, approved requirements, approved SOPs when changed or
referenced/process maps, and selected work packets into the coding executor
context.
The hand-written MCP software-delivery tools apply the same boundary. If
software_delivery_loop or software_spot_weld_fix receives a rough project,
custom-agent, SOP, modernization, or repo-creation request without explicit
delivery-readiness context, it starts consulting_project_workflow instead of
dispatching directly to IT/Ops. Existing approved delivery loops should pass the
server-provided project_product_machine_execution_context; user-supplied
delivery-readiness flags or force_software_delivery_loop=true alone do not
bypass the consulting workflow for project/SOP/repo-build intent.
The compact backbone profile also applies that boundary to
dispatch_domain_agent for coding, IT/Ops, engineering, and product actions.
Project-build intent goes to the consulting workflow first; ordinary domain
analysis and explicitly approved delivery loops still dispatch normally.
The compact profile does not expose generic invoke_tool, so it cannot perform
a direct live connector write. Generic connector invocation on the trusted full
local profile follows the same policy for repo, workflow, and deployment writes
such as github.create_repository,
github.create_pull_request, github.trigger_workflow, and
github.create_deployment_status.
Every direct generated connector operation and generic invoke_tool call also
requires the exact governed custody envelope: authenticated Project UUID,
correlation project_ref, project-bound connector_account_ref, stable
business-action idempotency key, and claimed effect for server verification.
Missing custody returns governed_connector_context_required; writes still
pause for a Spring-owned approval and never fall back to legacy/default routing.
Only operations in Spring's versioned reviewed effect catalog are dispatchable;
unknown or unreviewed generated Tools remain fail-closed as WRITE until their
provider contract is audited.
Full-profile generated tools inherit the same guard, including generated
coding_* domain actions and generated github_* repo/PR/deployment tools.
Page Builder keeps a pure design-session escape hatch with
force_page_builder=true, but project-like page, portal, app, SOP, workflow, or
GitHub-backed site builds start in the consulting workflow first.
Direct code_workspace_chat calls follow the same front-door rule for explicit
custom-agent/SOP/project-build prompts, while ordinary bounded bug fixes and
existing workspace tasks continue to the selected workspace.
Hosted MCP for ChatGPT and Claude
Use the same hosted Streamable HTTP MCP endpoint when adding Lightbulb Partners to ChatGPT Apps/Connectors or to Claude web/desktop as a remote MCP server:
https://agents.lightbulbpartners.com/mcp/lightbulb
The endpoint advertises OAuth protected-resource metadata and sends users
through the Lightbulb login/onboarding flow when they are not already
authenticated. ChatGPT and Claude receive the same authenticated, scoped
Context Space and Dynamic Workflow authority. UI hosts do not run local
lifecycle hooks, so they should call context_open at session/task start,
context_pack before substantial reasoning, and context_checkpoint at stable
handoff or compaction boundaries. Every recalled result is explicitly framed
as untrusted historical evidence.
After auth, ChatGPT can call start_consulting_project to create
a Lightbulb Project Agent workspace, seed the Product Machine plan, start the
backbone consulting workflow, and open guided intake with the first question:
Map the first workflow: trigger, owner, systems, handoffs, pain point, approver, and proof it worked.
The ChatGPT component is advertised with current Apps SDK metadata:
_meta["openai/outputTemplate"] on the tool descriptor and
_meta["openai/widgetDescription"], _meta["openai/widgetPrefersBorder"], and
_meta["openai/widgetCSP"] on the ui://lightbulb/project-start.html resource.
Legacy ui.resourceUri and ui.csp metadata remain for host compatibility.
Use lightbulb_chat for general account analysis. Project-like requests,
custom-agent builds, SOP/process changes, repo creation, Code Workspace work,
deployments, and connector mutations should route to start_consulting_project
so requirements, scope, SOP impact or referenced SOPs, work packets, and HITL
approval gates are established before execution.
Local runtime documents
The managed local runtime creates <root>/Lightbulb Documents with Inbox,
Exports, and Templates for user-visible files, plus hidden service storage
under <root>/.lightbulb. See
docs/local-runtime-documents-and-autocompany.md in the platform repo for the
folder initialization and AutoCompany/RAG environment contract.
Trimming the tool surface (0.6.0+)
The MCP server can register a large non-private generated surface. Exact profile
counts and their source digests are generated in
../api-specs/lightbulb.capability-inventory.v1.json; documentation does not
maintain a second count. Most hosts should use the adaptive four-tool surface.
When a flat advanced catalog is required, set LIGHTBULB_MCP_NAMESPACES to
scope the generated tools:
{
"mcpServers": {
"lightbulb": {
"command": "lightbulb-mcp",
"env": {
"LIGHTBULB_URL": "https://agents.lightbulbpartners.com",
"LIGHTBULB_MCP_NAMESPACES": "finance,crm,gmail,slack,jira,github,notion"
}
}
}
}
Valid namespace tags include all 18 domains (finance, intuit, crm, legal, engineering, content, it_ops, commerce, product, hr, coding, document_intelligence, solver, customer_success, procurement, gtm, grc, smarthome) and every connector prefix (gmail, microsoft, teams, calendar, docs, drive, sheets, slides, notion, slack, jira, github, salesforce, hubspot, shopify, square, stripe, xero, quickbooks, clio, smokeball, monday, excel, iam, ecommerce, tasks, tickets, notifications). Hand-written control-plane tools (whoami, search_documents, dispatch_domain_agent, etc.) always register regardless.
Python SDK
The package ships versioned Connector Execution, executable primitive, and custom project contracts plus the platform client used by MCP. Those runtime contracts follow SemVer beginning in 0.14. The broad endpoint client remains beta, so pin a minor version and review release notes before upgrading.
from lightbulb import LightbulbClient, device_login
BASE = "https://agents.lightbulbpartners.com"
# Recommended for humans: OAuth2-style device flow (browser handles MFA)
auth, _expires = device_login(BASE, client_id="my-app")
client = LightbulbClient(BASE, auth=auth)
print(client.whoami())
result = client.dispatch("finance", action="chat", message="Summarize cash this week")
print(result.reply)
Company engines and formation (0.16.0+)
Four company-engine packs sit on one replay-fenced core: the growth engine,
the pipeline engine, the SaaS operating engine, and the company operating
system that binds engines to budget envelopes, a period cadence, and typed
signals.* routes. Every primitive is read-only and returns PREVIEW; Spring
authorizes publishing, sending, deploying, spending, and reallocation.
from lightbulb import LightbulbClient, compile_company_operating_blueprint
plan = compile_company_operating_blueprint("b2b_saas", {"name": "Maple Analytics"})
plan.envelopes # per-engine budget and dispatch cadence
plan.signal_routes # typed cross-loop signals and their consumers
plan.formation # the guided formation request preview (CA)
client = LightbulbClient("https://agents.lightbulbpartners.com", auth=auth)
formed = client.create_company(name="Maple Analytics", country="Canada", industry="Software")
formed.company_id, formed.region, formed.workspace_ready
create_company is available in Australia and Canada only (AU/Australia,
CA/Canada); any other country is rejected before a request is made. The
tenant comes from the credential, never from the caller.
Accounting control evaluators
Two deterministic, read-only finance primitives evaluate accounting packages without changing a ledger:
finance.evaluate_journal_entry_controlschecks double-entry balance, company/chart/currency/period scope, evidence freshness, segregation of duties, approval state, and required control gates.finance.evaluate_period_close_readinesschecks the trial balance, required reconciliations, consolidation entity packages, currency translation, intercompany matching, eliminations, evidence, and approval state.
from lightbulb import (
JournalEntryControlInput,
evaluate_journal_entry_controls,
)
inputs = JournalEntryControlInput.model_validate(accounting_control_packet)
evaluation = evaluate_journal_entry_controls(inputs)
print(evaluation.disposition) # blocked, indeterminate, or ready
print(evaluation.operation_digest) # content-bound operation input
print(evaluation.evidence_digest) # ordered evidence lineage
assert evaluation.posting_authorized is False
The typed results always keep posting_authorized=False or
close_authorized=False, including a ready result. The SDK evaluates the
supplied snapshot and carries operation/evidence digests; execution through the
primitive runtime also emits a completed read receipt with evidence lineage.
Spring remains the authority for tenant/company scope, persistence, RBAC,
approvals, audit, posting, and period close.
Stripe-to-ledger reconciliation
The typed reconciliation client reuses Spring's authenticated Stripe and QuickBooks/Xero path. The SDK validates the request and response; Spring owns company scope, connector selection and credentials, execution, persistence, and run IDs.
from lightbulb import FinanceReconciliationRequest
run = client.run_finance_reconciliation(
FinanceReconciliationRequest(
ledger_provider="auto",
simulation_mode="auto",
include_details=True,
),
company_id="00000000-0000-0000-0000-000000000003",
)
print(run.run_id, run.authority_level, run.control_summary.match_rate)
recent = client.list_finance_reconciliation_runs(
company_id="00000000-0000-0000-0000-000000000003",
limit=25,
)
stored = client.get_finance_reconciliation_run(
str(recent[0].run_id),
company_id="00000000-0000-0000-0000-000000000003",
)
simulation_mode="auto" preserves Spring's connector-aware fallback,
"simulation" forces synthetic scenario-grade data, and "live" fails if
the required live connections are unavailable. Live results remain
controlled_partial unless the server explicitly supplies stronger authority;
provider acceptance alone is not promoted. The same method names are available
through AsyncLightbulbClient's managed async bridge.
The production-dark journal-to-close lighthouse uses the separate
finance.reconcile_stripe_settlements Business Process Primitive. Its
deterministic candidate accepts a Spring-custodied complete-month QuickBooks or
Xero General Ledger plus Stripe settlement movements. V1892 provides the
distinct internal Spring/PostgreSQL materialization and readback boundary: it
independently reproduces the candidate and can persist immutable automatic-match
evidence, review proposals, and exception cases. This does not authorize
proposal acceptance, exception disposition, journal creation or posting,
period transition, close, connector certification, or production execution;
the hosted-worker gate remains disabled.
Investment and trading agent
The investment facade exposes the complete research, feature, AutoML, Prime/Puffer, portfolio, broker-readiness, paper-observation, and cash-request workflow surface without accepting tenant or user IDs from the caller. Scope continues to come from the authenticated client and selected company.
from lightbulb import InvestmentAgentClient
investment = InvestmentAgentClient(client)
features = investment.feature_engineering({
"symbols": ["AAPL", "MSFT"],
"feature_config": {"features": ["return_5d", "volatility_20d"]},
})
evidence = investment.alpha_discovery({
"symbols": ["AAPL", "MSFT"],
"feature_config": {"features": ["return_5d", "volatility_20d"]},
"label_definition": {"target": "forward_return", "horizon_days": 5},
"validation_plan": {"split": "purged_walk_forward", "embargo_days": 5},
})
training_plan = investment.plan_alpha_training({"strategy_id": "slow-alpha-v1"})
Effect-capable requests fail locally unless the caller supplies a granular
InvestmentEffectIntent. This is only a deliberate SDK acknowledgement; it is
never forwarded as approval and cannot bypass server-side RBAC, institutional
risk certificates, commercial admission, broker idempotency, or cash controls.
plan_alpha_training() and stage_cash_movement() always force their execution
flags off. Use AsyncInvestmentAgentClient for native async dispatch.
The same 20 actions are generated as direct MCP tools under the finance
namespace. Set LIGHTBULB_MCP_NAMESPACES=finance to expose them without loading
unrelated connector namespaces.
Email / password and 2FA
from lightbulb import login, complete_2fa_login, TwoFactorRequired
try:
auth = login(BASE, "you@company.com", "secret")
except TwoFactorRequired as exc:
code = input("Authenticator code: ").strip()
auth = complete_2fa_login(exc.base_url, exc.email, code)
client = LightbulbClient(BASE, auth=auth)
For MFA accounts, device login is usually simpler.
Async
from lightbulb import AsyncLightbulbClient, JwtAuth
async def main():
auth = JwtAuth(token="...", tenant_id="...", company_id=None)
async with AsyncLightbulbClient(BASE, auth=auth) as client:
me = await client.whoami()
Hot paths use native httpx.AsyncClient I/O. Every remaining public sync-client
operation is awaitable through a managed asyncio.to_thread bridge, and sync
generators are adapted for async for. Verify releases with:
assert AsyncLightbulbClient.async_parity_report()["parity_percent"] == 100.0
Refreshing expired JWTs
Pass auth_refresh and call refresh_auth() after an AuthenticationError, then retry:
from lightbulb import LightbulbClient, AuthenticationError
from lightbulb.auth import device_login
def refresh():
auth, _ = device_login(BASE, client_id="my-worker")
return auth
client = LightbulbClient(BASE, auth=initial_auth, auth_refresh=refresh)
try:
client.dispatch("crm", action="chat", message="hello")
except AuthenticationError:
if client.refresh_auth():
client.dispatch("crm", action="chat", message="hello")
Same pattern on AsyncLightbulbClient with await client.refresh_auth().
Exceptions (lightbulb.errors)
HTTP failures from LightbulbClient and AsyncLightbulbClient raise LightbulbError subclasses (not raw httpx.HTTPStatusError):
| Type | Typical status |
|---|---|
AuthenticationError |
401 |
PermissionDenied |
403 |
NotFoundError |
404 |
ValidationError |
400 / 422 (also subclasses ValueError) |
RateLimitedError |
429 (retry_after when present) |
ServerError |
5xx |
Helpers: from_response, wrap_http_error, raise_if_error (used internally; safe to call on any httpx.Response).
Messages avoid leaking raw response bodies; structured JSON fields like message / error are capped.
Deep wrappers (XeroAgentClient, connector clients) use the same HTTP stack and raise the same types.
Typed integrations
- Stripe:
StripeOrchestratorClient,StripeWorkflow - Xero:
XeroAgentClient,XeroPlaybook - Project AutoResearch:
ProjectAutoResearchClientfor a typed, company-pinned paid-run lifecycle - Project learning runs:
ProjectLearningClientfor selected-company inspect, prepare, and admission calls with scope/contract/request-digest validation over authenticated Spring responses - Shopify storefront planning:
plan_shopify_storefrontandPlanShopifyStorefrontPrimitivefor deterministic, proposal-only plans - Omnichannel launch planning:
plan_omnichannel_product_launch,compile_product_launch_portfolio,create_product_launch_evaluation_loop, andevaluate_product_launch_iterationfor proposal compilation, bounded portfolio partitioning, control-state seeding, and verified post-launch decisions across Shopify, CRM, and social surfaces; these APIs do not execute a live connector loop - Connectors:
SlackClient,JiraClient,BambooHRClient,GreenhouseClient,MondayClient(thininvoke_tool/ HR-live helpers)
Project AutoResearch accepts only a project ID (or run ID for status/cancel).
Spring derives the objective, connected data, provider, immutable budgets,
tenant, company, and actor from authenticated state. Starting a paid run and
cancelling one both require literal caller confirmation; the SDK serializes
those confirmations into the request and Spring verifies them alongside the
actor's automl.experiments.execute permission:
from lightbulb import ProjectAutoResearchClient
research = ProjectAutoResearchClient(client) # client has a selected company
started = research.start(
project_id,
idempotency_key="research-q3-market-1",
confirm_paid_run=True,
)
current = research.status(started.run_id)
cancelled = research.cancel(
started.run_id,
reason="Superseded by the approved brief",
confirm_cancel=True,
)
ProjectLearningClient.list() (also exposed as inspect()) reads the latest
persisted receipt snapshot; it is not live worker telemetry. prepare() binds
an immutable training dataset to a queued durable run, and admit() reserves
capacity and makes that run eligible for a fenced worker claim. Neither method
executes training, claims a worker, promotes a model, or grants production
authority. The returned prepared/admitted models are sanitized local summaries,
not authenticated receipt containers, and cannot be passed to
project_learning_receipt_to_workflow_event(...).
Normalized learning receipts and ledgers expose actor_binding. It is
verified_against_auth_strategy only when the configured auth strategy exposes
a user ID and the returned receipt owner matches it. JWT sessions, empty
ledgers, and authorized colleague-owned ledger rows report
spring_enforced_not_locally_reverified: Spring remains the RBAC and actor
authority, and the SDK does not add a hidden whoami request.
from lightbulb import (
LearningCapacityAdmission,
ProjectLearningClient,
ProjectLearningRunAdmissionInput,
ProjectLearningRunPrepareInput,
)
learning = ProjectLearningClient(client) # selected company is mandatory
prepared = learning.prepare(
project_id,
ProjectLearningRunPrepareInput(
training_pack_receipt_id=training_pack_receipt_id,
primary_metric="validation_accuracy",
runtime="spark_feature_matrix",
confirmation="publish_dataset_and_create_queued_learning_run",
idempotency_key="feature-matrix-2026-07-30",
),
)
admitted = learning.admit(
project_id,
prepared.learning_run_id,
ProjectLearningRunAdmissionInput(
runtime="spark_feature_matrix",
capacity_admission=LearningCapacityAdmission(
schema="lightbulb.learning-capacity-plan.v1",
decision_id="capacity-decision-42",
runtime="spark",
admission="admit",
target_instances=2,
expires_at=capacity_expires_at,
secrets_redacted=True,
),
confirmation="reserve_budget_and_admit_durable_learning_run",
),
)
The Shopify primitive converts a typed storefront brief into ordered draft product, collection, and page proposals. A coding agent may turn a natural language prompt into that typed input, but the primitive itself makes zero connector calls. It does not generate/upload a custom theme, mutate a live store, deploy, or publish. Default product prices are preserved; additional variant creation remains an explicit capability gap. The requested currency is also retained in the plan, but materialization must read and verify the connected shop currency before applying prices.
from lightbulb import plan_shopify_storefront
plan = plan_shopify_storefront(
{
"brief": {
"storefront_name": "North Star Goods",
"brand_summary": "Practical tools for focused teams.",
"target_audience": "Professional-services teams.",
"business_goal": "Prepare a storefront for human review.",
"default_currency": "CAD",
"locale": "en-CA",
},
"products": [
{
"product_ref": "focus-kit",
"title": "Focus Kit",
"price": {"amount": "49.00", "currency": "CAD"},
}
],
"collection": {
"collection_ref": "featured",
"title": "Featured",
"product_refs": ["focus-kit"],
},
"pages": [],
"existing_theme": {
"strategy": "retain_existing",
"reference_name": "Current storefront theme",
},
}
)
assert plan.live_store_changed is False
Omnichannel product-launch proposals and governed control-state seeds
gtm.plan_omnichannel_product_launch turns one reviewed product, sales
campaign, social campaign, and set of normalized analytics snapshots into a
deterministic cross-surface proposal graph. The Shopify path is ordered
DRAFT create -> ACTIVE update -> explicit shopify.publish_product for the
brief's publication_ids -> gtm.verify_landing_readiness. Analytics-ranked
social proposals remain blocked behind that landing-readiness evidence gate.
HubSpot campaign creation is a domain action that creates a container only,
and every proposed write has a content-bound approval unit. Compilation makes
zero connector or domain calls.
from lightbulb import (
PlanOmnichannelProductLaunchPrimitive,
create_product_launch_evaluation_loop,
plan_omnichannel_product_launch,
)
launch = plan_omnichannel_product_launch(
PlanOmnichannelProductLaunchPrimitive.example_inputs
)
assert launch.proposal_only is True
assert launch.effect_boundary.writes_executed == 0
operations = {operation.capability: operation for operation in launch.operations}
draft = operations["ecommerce.create_product"]
activation = operations["ecommerce.update_product"]
publication = operations["shopify.publish_product"]
readiness = operations["gtm.verify_landing_readiness"]
assert draft.arguments.status == "DRAFT"
assert activation.arguments.status == "ACTIVE"
assert publication.depends_on == (activation.operation_id,)
assert readiness.depends_on == (publication.operation_id,)
provider_inputs = activation.connector_inputs({
draft.operation_id: {"product_id": "gid://shopify/Product/123"},
})
assert provider_inputs == {
"status": "ACTIVE",
"product_id": "gid://shopify/Product/123",
}
# The control-state seed is intentionally stricter than proposal compilation.
# Re-plan with host-HMAC snapshots, destination bindings, and exact authority.
host_bound_launch = plan_omnichannel_product_launch(
reviewed_launch_input,
verified_scope=authenticated_dynamic_workflow_scope,
scope_keyring=host_receipt_keyring,
connector_account_bindings=host_account_bindings,
)
loop = create_product_launch_evaluation_loop(
host_bound_launch,
scope=authenticated_dynamic_workflow_scope,
scope_keyring=host_receipt_keyring,
created_at=workflow_start_time,
)
assert loop.limits.max_iterations <= 4
ProductLaunchOperation.connector_inputs(...) removes internal SDK
discriminators and resolves declared output-to-input bindings before a host
dispatches an approved connector or domain operation. Evidence-gate operations
are not connector calls and reject this conversion.
Trusted hosts can execute the complete Shopify storefront tracer with
run_shopify_product_launch(...): DRAFT creation, ACTIVE transition, explicit
publication IDs, then a read-only live-landing readiness gate. Preview mode
does not query either the connector executor or readiness reader. Apply mode
stops at the first missing approval, blocked operation, failed operation, or
unproven read and can be resumed with no caller-owned checkpoint. Earlier
writes replay through stable per-operation idempotency keys and their outputs
and provenance are verified again before an output binding reaches the next
operation.
bind_product_launch_operation_approval(...) binds a different opaque
platform approval reference and platform-verified approval receipt digest to
each exact write's plan, scope, account, operation digest, and approval unit,
then HMAC-seals the grant. The older
bind_shopify_draft_product_approval(...) convenience wrapper remains for the
single-DRAFT API. Spring remains authoritative for ApprovalTask approval and
consumption.
A nominal connector COMPLETED status is deliberately insufficient. The
executor must return ConnectorExecutionProvenance containing the immutable
server request and receipt digests, authenticated project UUID, Tool version,
actual connector account and Tenant Connector, exact lowercase route digest,
approval reference and receipt digest, journal reference, authoritative
completion time, and provider response digest. Creation output must prove DRAFT;
activation output must prove the same product is ACTIVE; the native
publication response must then prove the same product, success=true, and
exactly the signed publication IDs. ACTIVE remains dependency-proven by the
immediately preceding activation receipt because Shopify's publication response
does not repeat product status.
Missing, contradictory, or mismatched provenance produces a failed result and
no launch receipt.
The final gate calls ConnectorLandingReadinessVerifier (or another trusted
LandingReadinessVerifier) with a sealed LandingReadinessRequest. The
connector-backed implementation invokes the governed
shopify.verify_product_readiness read and verifies its exact provenance and
closed payload. Its typed observation must match the exact request,
project, connector account, URL, product ID/title, price, currency, publication
IDs, and post-publication time, and must prove page reachability, product
visibility, price/currency agreement, and checkout availability. Missing or
generic connector output cannot fabricate readiness. CRM and social operations
are never dispatched by this runner and remain held until that receipt exists.
After readiness, the result exposes only the next graph-eligible downstream
operation: a configured CRM campaign becomes eligible first, while social
publication remains held until that campaign also has evidence. Even after
readiness, omnichannel_launch_completed remains false.
from lightbulb import (
bind_product_launch_operation_approval,
run_shopify_product_launch,
)
write_operations = [
operation
for operation in host_bound_launch.operations
if operation.capability in {
"ecommerce.create_product",
"ecommerce.update_product",
"shopify.publish_product",
}
]
grants = [
bind_product_launch_operation_approval(
host_bound_launch,
scope=authenticated_dynamic_workflow_scope,
scope_keyring=host_receipt_keyring,
operation_id=operation.operation_id,
approval_ref=approved_platform_tasks[operation.operation_id].ref,
approval_receipt_digest=(
approved_platform_tasks[operation.operation_id].receipt_sha256
),
)
for operation in write_operations
]
storefront_result = run_shopify_product_launch(
host_bound_launch,
scope=authenticated_dynamic_workflow_scope,
scope_keyring=host_receipt_keyring,
execution_scope=authenticated_project_execution_scope,
executor=account_bound_governed_executor,
run_ref="focus-kit-launch-1",
preview_only=False,
approval_grants=grants,
readiness_verifier=trusted_live_storefront_reader,
)
assert storefront_result.storefront_ready is True
assert storefront_result.omnichannel_launch_completed is False
Hosted completion requires the Spring authority to route the exact signed
connector_account_ref and return the complete custody envelope. Any older or
partially deployed authority fails closed. The in-memory adapter can exercise
the contract in tests and sandbox host implementations without weakening
production custody. The SDK never infers readiness from write success.
Discover the exact account alias from the authenticated project instead of guessing a default:
bound_accounts = client.list_project_connector_accounts(
project_id,
company_id=company_id,
)
shopify_account = next(
row for row in bound_accounts if row["provider"] == "shopify"
)
connector_account_ref = shopify_account["connectorAccountRef"]
list_available_project_connector_accounts(project_id, provider) mirrors the
trusted account-selector read for a binding UI. Both client methods delegate
tenant/company/project access and RBAC enforcement to Spring. For agent use,
the read-only MCP tool list_project_connector_accounts emits a compact
whitelist containing only provider, alias, account label, target resource, and
status; it never returns OAuth connection IDs or credentials. Its sanitized
rows are sorted deterministically and paged with bounded offset/limit
arguments (maximum 40 per page). Continue with the returned next_offset while
has_more is true; total_count is computed after sanitization and the optional
provider filter, so fleets larger than 40 accounts remain completely discoverable
without overlapping pages.
Resolve the execution coordinates from Spring rather than reading platform tables or guessing a Tool version:
from uuid import UUID
readiness_descriptor = client.get_project_connector_route_descriptor(
project_id,
connector_account_ref,
"shopify.verify_product_readiness",
company_id=company_id,
)
analytics_descriptor = client.get_project_connector_route_descriptor(
project_id,
connector_account_ref,
"shopify.analytics_query",
company_id=company_id,
)
trusted_live_storefront_reader = ConnectorLandingReadinessVerifier(
account_bound_governed_executor,
execution_scope=authenticated_project_execution_scope,
tenant_connector_id=UUID(readiness_descriptor["tenantConnectorId"]),
expected_tool_version=readiness_descriptor["toolVersion"],
expected_route_digest=readiness_descriptor["routeDigest"],
)
storefront_observation_route = StorefrontObservationRoute(
provider="shopify",
connector_account_ref=connector_account_ref,
tenant_connector_id=UUID(analytics_descriptor["tenantConnectorId"]),
expected_tool_version=analytics_descriptor["toolVersion"],
expected_route_digest=analytics_descriptor["routeDigest"],
)
AsyncLightbulbClient.get_project_connector_route_descriptor(...) provides the
same read through the managed async bridge. The authenticated endpoint resolves
the same project/account/Tool authority used for governed execution and returns
only projectId, connectorAccountRef, optional targetResourceRef, toolName,
toolVersion, tenantConnectorId, and routeDigest. The read-only MCP tool
get_project_connector_route_descriptor exposes a snake-case allowlist of those
fields and discards OAuth IDs, credentials, connector configuration, and any
unexpected response fields. Pass its route_digest back as expected route
custody for that exact Tool; never infer, synthesize, or reuse one Tool's route
digest for another Tool. Discovery is available only when the
governed connector boundary is enabled: authentication/scope failures remain
401/403, inactive or missing routes remain 404, ambiguous/drifted custody
remains 409, and a Tool without a server-owned effect classification remains
422. Hosts must surface those failures rather than falling back to database
lookups or a generic connector adapter.
The verified analytics path requires every normalized snapshot to name its
connector_account_ref and evidence digest. After validating the underlying
connector receipt, the trusted host calls
mint_product_launch_analytics_snapshot(...); its HMAC covers the complete
provider/account/window/metrics/evidence payload and the exact authenticated
scope. The host separately seals every Shopify, CRM, and social destination
with mint_product_launch_connector_account_binding(...). Pass the complete
set as connector_account_bindings= with that same verified_scope= and
scope_keyring= when planning. Merely copying a visible scope digest, account
ref, or evidence digest cannot produce a trusted plan. The host-bound plan is
itself HMAC-sealed, so reconstructing or editing its graph, policy, accounts, or
receipt obligations invalidates trusted loop admission.
For a host-HMAC-bound plan, a trusted host can mint one
mint_product_launch_receipt(...) per required criterion after it validates
the underlying live artifacts. Each receipt is HMAC-sealed and bound to the
exact scope, immutable plan digest, and, where applicable, operation ID and
digest. A write receipt additionally binds the exact approval_unit and a
host-verified approval receipt digest; non-write receipts cannot carry one.
Receipts are also bound to one loop run_ref and iteration.
verify_product_launch_receipts(...) requires the complete exact
receipt set, fails closed on binding, timing, freshness, sample, or HMAC
mismatches, and returns the EvidenceRef values that may be admitted to
Dynamic Workflow. Performance receipts carry an explicit observation window;
its duration must meet measurement_window_hours, so an immediate metric sample
cannot prematurely satisfy a multi-day policy, and its start must follow every
required operation and landing-readiness gate completion.
evaluate_product_launch_iteration(...) first performs that complete receipt
verification, then deterministically compares the verified performance metric
with the immutable target. It returns target_met, revise_plan, or
iteration_limit_reached plus the next iteration when applicable. The returned
evaluation is host-HMAC sealed; later iterations require that exact prior
revise_plan evaluation and newly attested evidence after its timestamp. KPI
comparison is produced by the evaluator rather than circularly required as an
input receipt. Replaying one receipt set produces the same signed evaluation
and deterministic commitment_ref; a durable host must accept only one digest
for each commitment. It does not revise a plan, grant a new approval,
materialize a connector, or schedule its own next run.
create_product_launch_evaluation_loop(...) seeds the existing generic
planner-builder-evaluator state machine with finite limits and receipt-kind
acceptance criteria. It rejects caller-unverified plans; pass scope_keyring=
with a host-HMAC-bound plan so the seed rechecks the exact scope. The seed still
does not materialize connectors,
validate approvals, mint or verify receipts on its own, schedule the
observation-window event, fetch post-launch analytics, or automatically revise
a campaign.
compile_product_launch_portfolio(...) partitions proposal records into at
most 12 launches and at most 100 estimated initial operations per shard. The
estimate covers only the initial graph. Serialized budgets are 256 KiB per job,
4 MiB per shard, and 64 MiB per portfolio. Distinct supplied
scope_fingerprint plus project_ref pairs remain separate, but those values
are partition keys rather than authority; a trusted host must derive or verify
them against the active authenticated scope before dispatch. The 10,000-launch
limit remains a count-validation ceiling, and byte budgets can reject a
portfolio earlier. Compilation is eager and in-memory and does not enforce
connector rate limits, spend limits, retries, or approvals. It never launches
stores, products, or campaigns.
The plan also records current execution gaps. The generated SDK/MCP connector surface now describes reviewed Facebook, Instagram, and LinkedIn publish operations, while paid-ad budget mutation and several broader ecommerce/social operations remain unavailable. Instagram native scheduling is unsupported; LinkedIn's current schedule route publishes immediately; and no typed action authors a complete HubSpot sales sequence. Agents can therefore use the plan without overstating what was materialized.
The SDK also ships the post-action observation rail. ObservationRuntime
schedules a full measurement window after the latest verified operation,
executes an exact-account governed shopify.analytics_query or
google_analytics.fetch_metrics read, normalizes the closed provider envelope,
and HMAC-seals its provenance. Connector schedules require the exact
expected_route_digest returned by descriptor discovery; the digest is sealed
inside ObservationJobSpec.job_digest and must equal the completed execution's
provenance.route_digest. Host-only observations omit route custody entirely.
schedule_storefront_phase(...) consumes exactly
the four real create, activate, publish, and landing-readiness receipts and
produces a distinct StorefrontPhaseEvaluation; that artifact reports only the
Shopify storefront phase and never claims omnichannel completion. The original
schedule_gtm(...) path remains closed-world and invokes the full launch
evaluator only after CRM, social, scope, and storefront receipts all exist. A
revise_plan verdict emits one idempotent phase-appropriate next-iteration
event; it never grants new write approvals itself.
JsonFileObservationArtifactRepository and ObservationWorker provide a
private, restart-safe single-host reference implementation. A production
application must still start that worker (or an equivalent queue/cron consumer)
and supply its authenticated scope partition; merely creating a checkpoint does
not wake a process.
LightbulbSoftwareFactoryRuntime.run_storefront_launch(...) is the durable
execution-to-learning join. After the exact storefront runner returns
storefront_ready, it immediately stores the content-addressed storefront
observation job before returning. Preview, approval waits, failures, and
unproven readiness schedule nothing. The same facade can drive the bounded
worker, but the embedding service must still start that process.
The remaining omnichannel work is narrower: CRM campaign materialization and the remaining social operations must consume the readiness receipt, and every new iteration still requires fresh approvals. The Shopify storefront tracer and its Shopify-or-GA evaluation path are executable through the shared governed connector rail; the SDK does not claim that a real store changed unless Spring returns exact route and execution provenance from a connected sandbox or production account.
Governed CRM communication engine
communication.plan_crm_conversation_turn is the proposal-only, Gmail-first
entry point for the communication engine. The sealed execution, observation,
replay, and CRM evidence rail also has closed provider adapters for Outlook,
Slack, and Teams; those adapters do not change the primitive's current Gmail
capability plan. The primitive accepts opaque CRM conversation, contact,
inbound-message, connector-account, and optional Growth artifact references
plus their content digests. It stores no recipient address, subject, message
body, or provider payload, invokes no connector, and returns an immutable plan
for these phases:
- resolve the canonical CRM context and exact Gmail route;
- evaluate consent, suppression, quiet hours, and frequency policy;
- draft private content outside durable workflow state;
- bind human approval to the exact content, audience, thread, route, and time;
- atomically reserve the contact slot;
- dispatch one governed in-thread Gmail message;
- observe a verified provider reply;
- classify it deterministically and propose review-only next actions; and
- append idempotent outbound, inbound, and reply touchpoints to CRM.
from lightbulb import PlanCrmConversationTurnInput, plan_crm_conversation_turn
turn = plan_crm_conversation_turn(
PlanCrmConversationTurnInput(
analysis_as_of="2026-08-19T16:00:00Z",
plan_ref="acme-reply-turn-1",
objective_ref="crm-objective-acme-reply",
objective_digest="c" * 64,
turn_kind="reply_to_inbound",
purpose="sales",
crm_conversation_ref="crm-conversation-acme",
crm_contact_ref="crm-contact-acme",
source_message_ref="crm-message-42",
source_message_digest="a" * 64,
connector_account_ref="gmail-sales-primary",
)
)
assert turn.live_systems_changed is False
assert turn.durable_private_content_allowed is False
assert "gmail.send_email" in turn.required_capabilities
assert "gmail.get_thread" in turn.required_capabilities
Trusted hosts mint the sealed context, party, endpoint, thread, draft, contact
policy, approval, reservation, provider-event, and CRM receipt artifacts with a
CommunicationScopeKeyRing. materialize_gmail_communication_turn(...)
revalidates exact tenant/company/user/project UUID custody before I/O. Preview
makes zero connector calls. An approved send consumes its single-use contact
reservation immediately before connector execution, requires Spring provenance
for the exact Tool version, Tenant Connector, account alias, project, route,
request, approval, and completion time. The approval binds the exact thread
digest, version, state, participants, and RFC parent Message-ID; Gmail receives
thread_id and parent_message_id together. Contact slots are keyed to the
company, canonical contact/address, and contact window, so two agents or
projects cannot independently win the same outreach slot.
gmail.get_thread is a real reviewed READ Tool, not a catalog placeholder. Its
generated MCP function requires project UUID/ref, connector-account alias, and
effect="read"; it intentionally exposes no idempotency key. Spring returns at
most ten bounded messages only on the fresh response while durable journals and
provider audits retain commitments and counts. GmailCommunicationRuntime
is fed by GmailCommunicationObserver.poll_once(...), which performs one
fresh, non-replayable read through a separately attested read route. The
observer requires the read and sealed write routes to resolve to the same
project, connector account, and Tenant Connector. It derives the outbound RFC
Message-ID from the exact sent Gmail message in that fresh response, then
accepts a reply only when In-Reply-To or References names that parent. It
fails closed on truncation or ambiguity and persists no raw body, address,
message ID, or provider payload. The runtime then admits only a host-HMAC event
with verified authenticity, the exact
account/route/thread/outbound-message bindings, post-dispatch timing, and
matching transient content commitments. It deduplicates provider events and
messages across retries, records three content-free CRM touchpoint receipts,
and emits a CommunicationOutcomeObservation with
causal_claim_ready=False.
Provider truth is deliberately layered. materialize_gmail_communication_turn
marks a write complete only after validating Gmail's exact message and thread
response, but "complete" does not mean SMTP delivery, inbox placement, an open,
or a human read. For Outlook, materialize_outlook_communication_turn treats
Graph accepted=true as provider acceptance; only sentItemsObserved=true
upgrades that result to completed provider observation. A later bounded
OutlookCommunicationObserver read can independently establish that exact
outbound object and a threaded reply. It still does not prove transport
delivery or a human read.
materialize_slack_communication_turn and
materialize_teams_communication_turn validate one exact provider-created
message object. SlackCommunicationObserver and TeamsCommunicationObserver
then use separately attested, bounded thread reads to establish provider
observation and an inbound turn. Their public observation result fixes both
delivery_claimed and human_read_claimed to False. Across all four
providers, connector acceptance, provider observation, transport delivery, and
human reading are distinct facts; the SDK never upgrades one into another.
Reply interpretation never performs a business effect. Explicit unsubscribe,
legal/security, payment-dispute, meeting, positive, negative, and general
language produce deterministic scores and proposed capabilities, all marked for
human review. CRM remains the canonical customer timeline; this SDK does not
create another conversation database. The optional GrowthSourceBinding is
only an opaque, reviewed input binding. Funnel measurement, experiments,
learnings, transfer, and Growth re-planning remain owned by the Growth Engine.
The in-memory reservation, replay, and CRM sink implementations are reference adapters for tests and single-process hosts. A production deployment still needs configured durable custody adapters and a separately operated host worker/poller for bounded observations; this public SDK surface does not claim that a remote production worker is complete or start an autonomous scheduler. Hosted Gmail, Outlook, Slack, and Teams execution remains behind Spring feature flags that are off by default. Adding these APIs and tests changed no live mailbox or channel.
Ten-workflow contribution-profit flywheel
The SDK ships ten proposal-first workflows around the omnichannel launch. They optimize contribution profit instead of revenue, clicks, or headline ROAS. The shared ledger derives profit as gross sales minus discounts, refunds, COGS, fulfillment, payment fees, incremental acquisition, and incremental service costs.
| Order | Primitive | Profit job |
|---|---|---|
| 1 | finance.allocate_launch_portfolio_profit |
Attribute profit and issue bounded scale, hold, revise, or retire envelopes. |
| 2 | product.discover_profitable_opportunities |
Rank product/segment/store pilots and cheapest valid kill tests. |
| 3 | gtm.optimize_offer_price_and_margin |
Guard price, bundle, shipping, and discount experiments with margin floors. |
| 4 | commerce.govern_inventory_and_fulfillment |
Gate launch and acquisition on stock, cash, lead time, and fulfillment capacity. |
| 5 | commerce.optimize_storefront_conversion |
Plan previewable storefront experiments against profit per session. |
| 6 | content.run_creative_experiment_factory |
Select channel-native creative using downstream profit and fatigue evidence. |
| 7 | growth.allocate_incremental_acquisition |
Allocate only the next capped acquisition tranche with a stop-loss. |
| 8 | crm.orchestrate_profit_aware_lifecycle |
Choose consent-safe next-best actions by expected profit per contact. |
| 9 | commerce.recover_abandoned_revenue |
Recover checkout demand with the least costly valid intervention. |
| 10 | customer_success.prevent_returns_and_expand_ltv |
Prevent avoidable harm/returns and grow profitable repeat purchase. |
Every primitive uses the same bounded economics engine but a different code-owned blueprint: exact evidence sources, allowed action capabilities, required KPIs, direction, handoffs, and connector-truth gaps. Candidate economics are risk-adjusted for confidence, downside, and implementation cost. The bounded global selector maximizes total risk-adjusted contribution profit; capital efficiency and time-to-value are deterministic tie-breakers after the profit objective, while dependencies, mutual exclusion, cash budget, and action count remain hard constraints. Unverified evidence receives a configurable confidence haircut. No workflow accepts arbitrary connector tools or effects.
from lightbulb import (
PROFIT_WORKFLOW_DEFINITIONS,
compile_profit_flywheel,
plan_profit_workflow,
profit_workflow_example_inputs,
)
workflow_id = "commerce.recover_abandoned_revenue"
inputs = profit_workflow_example_inputs(workflow_id)
plan = plan_profit_workflow(workflow_id, inputs)
assert plan.effect_boundary.external_systems_changed is False
assert plan.effect_boundary.materialization_supported is False
assert all(action.dispatchable_by_planner is False for action in plan.actions)
# The manifest stores ten compact content-addressed nodes, not ten copied plans.
all_inputs = {
workflow_id: profit_workflow_example_inputs(workflow_id)
for workflow_id in (
definition.workflow_id for definition in PROFIT_WORKFLOW_DEFINITIONS
)
}
flywheel = compile_profit_flywheel(all_inputs)
assert len(flywheel.nodes) == 10
assert flywheel.external_workflow_refs == (
"gtm.plan_omnichannel_product_launch",
)
assert flywheel.estimates_are_non_additive is True
The public primitive path remains deliberately caller-unverified. A trusted
host first verifies connector receipts and exact tenant/company/user/project
scope. It HMAC-seals each opaque account reference with
mint_profit_connector_account_binding(...), seals account-scoped observations
with mint_profit_metric_evidence(...), and re-plans with verified_scope= plus
scope_keyring=. The host-bound plan and every content-bound approval are then
scope-specific. After each exact action is approved and executes elsewhere,
mint_profit_action_execution_receipt(...) binds its provider/artifact receipt,
approval receipt (mandatory for writes), account, operation digest, plan, run,
and iteration. mint_profit_outcome_evidence(...) requires the complete action
receipt set and a measurement window that starts after every action completed.
evaluate_profit_workflow_iteration(...) then returns target_met,
revise_plan, or iteration_limit_reached. Later revisions require the prior
signed revise_plan evaluation and a new post-evaluation window. A durable host
must enforce one commitment_ref/outcome digest per plan/run/iteration.
The planner never dispatches its intent_parameters; they are business intent,
not connector arguments. For the closed connector subset, typed candidate
builders commit the exact payload digest and run_profit_workflow_actions(...)
preflights the complete graph before its first effect. It then executes in
dependency order through materialize_profit_action(...), stops at the first
approval wait or failure, and resumes only from exact plan/run/iteration
receipts. Every write binds tenant, company, user, project UUID, project account
alias, Tool, arguments, approval receipt, idempotency identity, and Spring
execution provenance. Completed runs expose an observation-not-before time but
keep causal_claim_ready=False until ObservationRuntime evaluates the full
window.
The materializable adjacent subset now includes reviewed Shopify product
updates for offer/storefront optimization; Facebook, Instagram, and LinkedIn
creative cells; consent-safe Gmail lifecycle messages; and bounded Shopify
discount plus Gmail recovery graphs. Recovery shares the exact materializer and
provenance rail but the generic runner rejects it; use the recovery facade so a
fresh dispatch safety attestation cannot be bypassed. Use
build_offer_product_update_candidate(...),
build_creative_publish_candidate(...), or
build_lifecycle_email_candidate(...) to create the exact plan candidate.
LightbulbSoftwareFactoryRuntime.run_profit_workflow(...) joins a completed
offer, creative, or lifecycle action graph to its exact post-action observation
job. It schedules nothing for preview, approval waits, or failed effects.
Paid-ad budget mutation, a universal inventory mutation, and HubSpot sequence
authoring remain explicit gaps rather than simulated effects.
Abandoned-revenue recovery adds stricter business gates on top of that rail.
RecoveryIngestionWorker scans the exact governed Shopify account in at most
20-row cursor pages and at most 250 rows per run. It validates every page's
provenance and strict connector output, obtains short-lived host-HMAC
consent/inventory/frequency/economics facts, resolves email, recovery URL, and
code only transiently, and atomically checkpoints a scoped case and plan
without approving or dispatching writes. Hosts persist its returned
next_cursor to continue larger scans.
mint_abandoned_recovery_case(...) seals a privacy-minimized case; raw recipient,
recovery URL, and one-time discount code stay only at the execution boundary.
plan_abandoned_revenue_recovery(...) retains randomized holdouts and suppresses
unknown/withdrawn consent, exhausted frequency caps, expired or out-of-stock
checkouts, unprofitable outreach, and margin-eroding discounts. An eligible
treatment requires a fresh, short-lived
mint_recovery_dispatch_attestation(...) immediately before I/O; this
scope-HMAC proof rechecks consent, inventory, frequency count, case expiry, and
discount expiry. Live dispatch also requires a single-use transactional
RecoveryContactReservationAuthority, consumed only at the exact Gmail send;
the included in-memory authority is for tests and single-process hosts, while a
production host must supply durable atomic storage. It then runs an optional
one-use expiring discount before one approved Gmail message.
schedule_abandoned_recovery_observation(...) schedules a trusted
host.checkout_recovery_snapshot; its randomized-holdout ledger must cover all
targeted Shopify/Gmail accounts before the profit evaluator may report recovered
incremental contribution.
from lightbulb import (
LightbulbSoftwareFactoryRuntime,
mint_recovery_dispatch_attestation,
plan_abandoned_revenue_recovery,
)
recovery_plan = plan_abandoned_revenue_recovery(
host_attested_case,
resolved_secrets=execution_boundary_secrets,
analysis_as_of=host_clock,
scope=authenticated_scope,
scope_keyring=host_keyring,
)
dispatch_attestation = mint_recovery_dispatch_attestation(
recovery_plan,
host_attested_case,
consent_status=current_consent,
inventory_available=current_inventory_available,
prior_recovery_contacts=current_recovery_count,
observed_at=host_clock,
valid_until=host_clock + timedelta(minutes=5),
scope=authenticated_scope,
scope_keyring=host_keyring,
)
factory = LightbulbSoftwareFactoryRuntime(observation_runtime)
loop_result = factory.run_abandoned_recovery(
recovery_plan,
host_attested_case,
resolved_secrets=execution_boundary_secrets,
scope=authenticated_scope,
scope_keyring=host_keyring,
execution_scope=authenticated_project_execution_scope,
executor=governed_executor,
run_ref="checkout-recovery-1",
preview_only=False,
dispatch_at=host_clock,
dispatch_attestation=dispatch_attestation,
contact_reservation=transactional_contact_reservation,
contact_reservation_authority=durable_contact_reservation_authority,
approval_grants=approved_action_grants,
experiment_ref="checkout_holdout_1",
)
assert loop_result.status == "observation_scheduled"
assert loop_result.recovery.causal_claim_ready is False
For 100 stores by 100 products, use pilot-to-scale tranches rather than treating the existing 10,000-launch validation ceiling as permission or throughput. Per-store currency, tax, shipping, inventory, consent, connector quota, spend, dedupe, causal holdout, and automatic stop-loss gates remain mandatory.
Executable discovery is paged so these schemas remain usable by coding agents.
Both MCP catalogs default to bounded summary pages. Executable full-schema
queries return one primitive per page; business full-contract queries retain as
many matches as fit below the MCP payload ceiling. Follow next_offset for
broader queries, or request an explicit summary page. Direct Python catalog
callers retain the full-schema default and may request up to ten schemas per
page. Summary results expose searchable
capability_hints; exact executable results also expose a structured
profit_blueprint. Both are discovery contracts only—the proposal primitives
declare no connector tools and cannot dispatch the capabilities they describe.
Growth Engine
The Growth Engine is the SDK's analytics-to-action layer for cross-connector
growth work (Shopify, HubSpot, Salesforce, Meta, LinkedIn, Google Analytics).
It closes the loop measure → diagnose → experiment → learn → plan with
sealed, tamper-evident artifacts at every step. Full design:
docs/growth-engine-design.md; implementation contracts:
docs/growth-engine-build-contract-map.md.
Modules (naming note: growth_primitives.py predates this layer and is
unrelated catalog code):
| Module | What it owns |
|---|---|
growth_ingestion |
The engine's front door. normalize_connector_response turns a real connector analytics response (Shopify's columns/rows ShopifyQL table, GA's per-day metrics list, Meta/LinkedIn's nested vendor insight objects, HubSpot's deals list, Salesforce's aggregated report — mapped from the platform's own in-repo adapter contracts) into an unsealed GrowthFunnelEvidence body the host then seals. Only recognized fields map (others reported in a MetricCoverage); missing metrics stay absent (unknown ≠ zero); rates emit only from a provider's own [0,1] rate field, never derived; shape mismatches fail loudly; evidence_digest is the SHA-256 of the raw response so the evidence is bound to the exact bytes. HubSpot emits no won_deals (its search has no is_won flag — we don't guess). Capability-keyed and discoverable; sealing stays host-side. |
growth_funnel |
Canonical six-stage funnel (audience→traffic→engagement→conversion→revenue→retention) built from sealed GrowthFunnelEvidence envelopes. Unknown stages stay unknown; measurement bases never silently mix; exclusions are visible with reasons; bottlenecks name the reference they used. |
growth_experiments |
Preregistered experiments where the HMAC seal is the preregistration. Stdlib-only statistics (two-proportion z, Welch's t, chi-square SRM checks, Acklam+Newton quantiles), keyed deterministic assignment, fixed-horizon readouts that refuse peeking; causal=true is structurally impossible without a sealed design. |
growth_learnings |
Append-only, hash-chained, scope-bound growth memory. experimental entries can only be recorded from verified causal readouts; observational entries require evidence digests; heuristic entries rank last. Supersession, expiry, grade-ranked queries; loads fail closed on tampering. |
demand_gen_primitives |
Deterministic content-calendar and audience-growth planners aimed at the verified funnel bottleneck. Every item is a content brief bound to a rail-style approval unit over its content digest; planners never dispatch. |
growth_cockpit |
diagnose_growth(...): one ranked answer to "what should I do next" — bottleneck, opportunities with the exact next primitive and argument hints, evidence gaps with the connector capabilities that fill them, applicable learnings, data-quality notes. |
growth_portfolio |
The fleet layer for the N-store case (host-side only; inputs carry member scopes). Sealed portfolio rollups over per-store verified snapshots, portfolio_sibling benchmark references from fleet medians, honest cross-store learning transfer (always observational — the experiment didn't run there), and portfolio diagnosis: cluster stores by shared bottleneck, run ONE experiment on representative test stores, transfer the learning, roll out. |
growth_workspace |
Durable, scope-bound persistence for the whole engine. Content-addressed artifact files + a revisioned index; sealed artifacts verified on save AND on every load (verified in, verified out); coherence rules (design before evidence/readout, exactly one readout per design, dispatch before receipts); deterministic lifecycle queries (experiment_status(as_of), pending_readouts(as_of), status(as_of)); owns the scope's learnings ledger. Seal a design today, read it out at the horizon weeks later — across sessions. |
growth_rail_bridge |
The two-way seam with the governed execution rail, strictly at the dict boundary (no imports either way). Outbound: author_calendar_item binds byte-exact copy to a plan brief, compile_content_calendar_dispatch emits a sealed package of rail-shaped social_publish operations using the rail's exact capability names, argument models, content-digest recipe, and approval units. Inbound: rail receipts verify under the rail's own HMAC domain and reconcile_dispatch_receipts matches them by exact operation digest, reporting completed/pending honestly and deriving measure_after (measurement opens after the LAST completed action). Nothing here executes; dispatch belongs to the rail behind its own approvals. |
growth_operating |
The conductor. compile_growth_agenda joins workspace state into one ranked, argument-hinted agenda under a fixed precedence — due readouts (a missed fixed-horizon readout is paid-for traffic earning zero learnings), unrecorded causal learnings, receipts to reconcile, post-action measurement windows (opening strictly after measure_after), stale evidence per a caller-supplied heuristic GrowthCadencePolicy, then opportunities cited verbatim from the stored diagnosis and profit review — with duplicate experiments emitted blocked (naming the in-flight design), source_digests on every item, and idle/wake_at so a scheduler knows exactly when to bring the agent back. compare_funnel_snapshots answers the operator's weekly question — did last week's work move anything — with every delta structurally labeled observational_movement_not_attribution, unknown staying unknown, and cross-scope comparison refused. GrowthWorkspace.compile_agenda(as_of) is the one-call session bootstrap; a kind-coverage test guarantees every workspace artifact kind is either consumed by the agenda or explicitly declared exempt. |
growth_objectives |
The destination. A sealed GrowthObjective commits the scope to a contribution-profit run-rate by a deadline, with the baseline DERIVED from verified unit economics at commit time (the seal is the commitment — goalposts cannot quietly move; a new target names what it supersedes). assess_objective_progress judges the current window-normalized run-rate against a labeled linear glide path (on_track / at_risk / off_track / achieved / expired_missed), prices the remaining money gap, and — given the profit and customer-value reviews — reports what their dollar-ranked opportunities could fund versus the unfunded shortfall. The conductor demands assessment when it is missing or stale, frames every agenda with the gap, and treats a missed deadline as a demand for a superseding objective, never a quiet re-baseline. |
growth_mandate |
Bounded autonomy. A sealed GrowthMandate is the human's delegation contract: which action kinds the agent may take without asking (adjust_channel_budget, launch_experiment, publish_content, price_move), a money ceiling per action and a rolling-window ceiling per kind, guardrails pinned to sealed evidence (economics-component floors/ceilings, and objective-verdict allowlists whose verdict the gate derives itself from the verified objective and economics — advisory assessments are caller-forgeable, so it accepts none), and a mandatory expiry — open-ended authority is structurally refused. authorize_growth_action (host path) verifies everything sealed and mints a sealed ActionAuthorization for every verdict — authorized, escalate, or refused — so denials leave the same audit trail as approvals. Silence never authorizes: an unevaluable guardrail escalates; a prior receipt that fails verification escalates; over-ceiling asks escalate (the human can still say yes personally). GrowthWorkspace.authorize_action is the one-call agent gate with complete stored-receipt window accounting, and the conductor surfaces expired/expiring mandates and pending escalations as mandate_attention. Authorization is not execution — a receipt says "within delegated bounds at decision time", never "it happened". |
growth_briefing |
Session rehydration for a mind that reboots. compile_growth_briefing (and the one-call GrowthWorkspace.compile_briefing) renders the compiled agenda plus the scope's sealed artifacts — objective status, the ranked do-this-now list, remaining mandate authority per action kind, unit economics, funnel state, in-flight experiments, banked learnings — into deterministic plain text that fits a stated character budget. The briefing renders, it never re-decides: every number is quoted from a digest-pinned artifact, the only added arithmetic (summarize_mandate_spend) is test-pinned to the sealed gate's receipts, dropped sections are named with where to fetch them, a budget below the honesty floor is refused, and trust is echoed from the agenda's join, never upgraded. |
growth_money_ingestion |
The front door for the money envelopes. normalize_contribution_ledger_response maps a Shopify ShopifyQL ledger table to unsealed ProfitContributionEvidence (costs Shopify cannot see — ad spend, service costs — stay absent, never zero); normalize_customer_cohorts_response maps a cohort-grouped table (one row per cohort-month × age bucket) to unsealed CustomerCohortEvidence with month-derived acquisition windows and per-cohort provenance digests. Same honesty rules as growth_ingestion: recognized columns only, unmapped numerics reported, loud shape mismatches, digests bound to the raw response. Finance-side capabilities are refused loudly until their response shapes are pinned. Sealing stays host-side. |
growth_customers |
The repeat-purchase dollar. Sealed CustomerCohortEvidence (acquisition cohorts with half-open age buckets) pools into horizon-bounded observed customer value — net revenue and orders per customer at 30/90/180/360 days, contribution LTV via a verified economics margin (cross_artifact-labeled, digest-pinned), and the CAC ceiling it supports. Right-censoring is structural: cohorts too young for a horizon are excluded with a reason, never averaged in, and value beyond the observed horizons stays unknown. review_customer_value prices ceiling headroom in contribution dollars against the ledger's CAC (raise or cut, with scenario intervals), demands missing evidence, and hooks a preregistered purchase_to_repeat experiment where the pooled reorder curve fades. The payback horizon is labeled a finance-policy heuristic everywhere it appears. |
growth_profit |
The money model. Sealed ProfitContributionEvidence envelopes (rail-vocabulary ledger fields: gross_sales, discounts, refunds, cogs, fulfillment_cost, payment_fees, acquisition_cost, service_cost) roll up into a UnitEconomicsSnapshot — net revenue, contribution profit/margin, AOV, CAC, breakeven ROAS, CAC payback — with per-metric completeness (unknown is not zero), currency and basis separation, and visible exclusions. review_profit prices funnel-rate gaps in contribution dollars with scenario intervals, screens cost leaks against labeled heuristics, and names the exact next primitive. plan_price_move plans one bounded price change (protect a breached margin floor / probe elasticity / grow contribution under a measured elasticity) — the margin floor is structurally enforced, the move is bound to a content-digest approval unit, and the plan embeds the exact preregistered revenue_per_session experiment to run. estimate_price_elasticity turns that experiment's causal readout into an arc-elasticity estimate with a propagated interval, ready for the learnings ledger (lever="pricing"). |
Agent-discoverable executable primitives (also reachable through the generic
MCP primitive tools): growth.build_funnel_snapshot, growth.diagnose,
growth.build_unit_economics, growth.review_profit,
growth.plan_price_move, growth.compile_agenda,
growth.compare_funnel_snapshots, growth.build_customer_value,
growth.review_customer_value, growth.assess_objective,
growth.preflight_action, growth.compile_briefing,
demand_gen.plan_content_calendar,
demand_gen.plan_audience_growth. They
run the honest unverified path (caller_supplied_unverified); sealing
happens host-side through the module functions with a
DynamicWorkflowReceiptKeyRing.
The compounding loop, end to end:
from lightbulb import (
GrowthLearningsLedger, InMemoryLedgerStore,
build_growth_funnel_snapshot, design_growth_experiment, diagnose_growth,
mint_growth_funnel_evidence, read_out_growth_experiment,
)
# 1. Seal connector observations, build the funnel (host-side, keyed).
evidence = mint_growth_funnel_evidence(raw_observation, scope=scope, scope_keyring=ring)
snapshot = build_growth_funnel_snapshot(
{"analysis_as_of": now, "snapshot_ref": "week-34", "evidence": (evidence, ...)},
scope=scope, scope_keyring=ring,
)
# 2. Diagnose: ranked opportunities with the exact next call.
diagnosis = diagnose_growth({"as_of": now, "funnel_snapshot": snapshot})
# 3. Preregister the experiment the diagnosis suggested (the seal IS the
# preregistration; required sample size is recomputed and enforced).
design = design_growth_experiment({...}, scope=scope, scope_keyring=ring)
# 4. After the horizon: honest readout (SRM-checked, no peeking, CI + verdict).
readout = read_out_growth_experiment(design, arm_evidence, readout_ref="r1",
analysis_as_of=later, scope=scope, scope_keyring=ring)
# 5. Record it — future plans across the whole portfolio can now cite it.
ledger = GrowthLearningsLedger(InMemoryLedgerStore(), scope=scope, scope_keyring=ring)
ledger.record_experiment_learning(design=design, readout=readout, entry_ref="anchor-pricing",
lever="price_anchoring", claim="...", recorded_at=later)
Boundary (stated, not hidden): the Growth Engine plans, measures, and learns. Live connector execution of its plans flows through the governed execution rail (approvals, receipts, provenance) — plan items carry rail-compatible content-digest approval units so they become executable there without re-planning.
Security posture
- HTTPS enforced for non-local hosts by default (
enforce_https=Falseonly for dev). - Path segments and risky inputs validated (
validatorsmodule); SSO / device-flow URLs validated before opening a browser. - Token cache: atomic write, restrictive permissions, symlink and ownership checks.
lightbulb setup: atomic config writes, safe TOML escaping for Codex, backups chmod-restricted.
Regression tests live in tests/test_security.py (audit IDs in docstrings).
Types (PEP 561)
The wheel ships py.typed for Pyright/mypy consumers.
Version history
0.16.0
- Added four company-engine Golden Operating Loop packs on a shared
replay-fenced engine core (
lightbulb.company_engine_core): the growth engine (growth.store_truth_to_attributed_revenue@0.1.0), the pipeline engine (revenue.icp_to_qualified_pipeline@0.1.0), the SaaS operating engine (saas.launched_product_to_compounding_revenue@0.1.0), and the company operating system (company.blueprint_to_governed_operating_cadence@0.1.0). Twenty-one new read-only executable primitives (growth_engine.*,pipeline.*,saas_ops.*,company.*, and theirblueprint.compile_*entries) bring the registry to 202; the MCP catalogs project them to Claude Code, Codex, Cursor, and ChatGPT unchanged. - Added
LightbulbClient.create_companyandAsyncLightbulbClient.create_company: form a company through the signed-in user's own Lightbulb account viaPOST /api/companies/guided. Australia and Canada only; the tenant always comes from the credential and Spring authorizes the caller as a tenant admin. - Added typed cross-loop signals (
signals.*) with producers, enabled consumers, and required payload keys; routing advises and never executes. - Regenerated the released-authority manifest, the primitive capability
manifest, and the capability inventory. See
docs/lightbulb-company-engines.mdin the monorepo for the full contract.
0.15.0
- Expanded the SDK to 93 evidence-bound executable primitives across accounting, procure-to-pay, supply chain, manufacturing/field quality, commercial, customer service, people, product, compliance, omnichannel policy/outcomes, connector certification, and production readiness. This includes governed journal discovery/preparation/post/readback plus bounded vendor-onboarding, procure-to-pay, finance-close, supply-chain execution, manufacturing-execution, commercial-operations with exact flat/seat/usage/hybrid billing branches, customer-service, people-operations, product-engineering, and compliance-risk lifecycle surfaces.
- Added verified project-envelope worker identity, exact connector-account custody, versioned operation/evidence/recovery receipts, no-replay handling for ambiguous writes, and a Spring-authoritative reviewed finance-write lane.
- Added self-binding result digests and completed read-only operation receipts across the operating-domain evaluators; receipts attest deterministic SDK evaluation only and never provider truth, approval, persistence, or authority.
- Added persisted bounded workflow loops with exact continue/terminal edges and crash-resume budgets, plus governed SMS/WhatsApp materializers, a sealed WhatsApp webhook observer, cross-channel identity and consent policy, normalized provider outcomes, and voice-call planning/observation contracts.
- Added exact project-account connector routing and Spring execution provenance, a resumable Shopify DRAFT → ACTIVE → publication → landing-readiness runner, durable Shopify/Google Analytics observation workers with automatic signed evaluation, and randomized-holdout abandoned-revenue recovery.
- Added a shared approved profit-action execution rail plus materializable offer, storefront, creative, lifecycle-email, and recovery candidates. External effects remain separately approved and outcome claims remain evidence-gated.
- Added ten typed contribution-profit workflows, exact-scope account, metric, plan, approval/action, outcome, and evaluation receipts, a globally profit-maximizing bounded selector, a compact launch-anchored flywheel manifest, and paged capability-searchable primitive discovery.
- Added the omnichannel Shopify/CRM/social launch compiler with destination account attestations, per-write approval receipts, post-action measurement windows, deterministic evaluation commitments, and bounded portfolio shards.
- Added governed default skill search with verified lifecycle metadata, outcome receipts, and tenant/company/project scope preservation.
- Added typed learning primitives, project AutoResearch, durable project-learning events, workflow improvement integration, and Shopify business primitives.
- Added durable retries and executable business-primitive discovery so agentic workflows can learn from AutoML, GEPA, Prime, and Puffer-backed execution without bypassing platform governance.
- Added the Growth Engine: twelve modules closing the loop measure → diagnose → preregister → read out → learn → transfer → price → plan → conduct → dispatch, with HMAC-sealed artifacts, structural causal honesty (no causal claim without a sealed preregistration), and unknown-never-zero semantics throughout.
- Added the canonical six-stage funnel from sealed cross-connector evidence (
growth_funnel), the preregistered experiment engine with stdlib-only statistics and fixed-horizon readouts (growth_experiments), and the hash-chained learnings ledger with structural evidence grades (growth_learnings). - Added the money models: unit economics with contribution margin/CAC/breakeven ROAS and margin-floor-enforced price experiments with measured elasticity (
growth_profit); horizon-bounded observed customer LTV under a structural right-censoring law, CAC ceilings, and reorder-timing curves (growth_customers). - Added the operators: ranked diagnosis (
growth_cockpit), bottleneck-aimed demand-gen planners with content-digest approval units (demand_gen_primitives), the one-call operating agenda with duplicate-experiment blocking and scheduler wake semantics (growth_operating), fleet rollups and observational learning transfer (growth_portfolio), and durable verified-in/verified-out persistence (growth_workspace). - Added evidence ingestion for real connector responses — funnel envelopes (
growth_ingestion, Meta field maps live-validated) and the money envelopes for contribution ledgers and acquisition cohorts (growth_money_ingestion) — plus the dict-boundary execution-rail bridge with byte-exact mirrored contracts (growth_rail_bridge). - Added 12 read-only executable growth primitives (bringing the then-current communication/GTM/profit/growth subset to 39), 19 workspace artifact kinds, and full public exports; four adversarial audit rounds (79 confirmed findings) closed with regression tests.
0.14.1
- Added opaque
runtime_agent.<uuid>references for approved authored-agent revisions, strict recursive policy validation, and the governed author → review/approve → explicitly provisioned recursive-spawn contract. - Added exact-scope Spring preflight, digest/model/policy verification, immutable per-run manifests, least-privilege tool intersection, disabled child delegation, and public SDK/MCP guidance without activating ordinary domain dispatch.
0.14.0
- Added typed Connector Execution requests/results with hosted and in-memory adapters, normalized failures, preview-only writes, approval enforcement, request recording, and idempotent replay protection.
- Added 13 executable business process primitives with Pydantic input/output contracts, including reply classification, email, invoice, meeting scheduling, governed payment collection, decision requests, business artifact generation, and implementation work packets.
- Added
LightbulbProject,ProjectRuntime, andDurableProjectRuntimefor project capability declarations, connector Tool allow-lists, deterministic bindings, revisioned pause/resume, schedules, idempotent events, and distributed worker leases. - Added automatic sanitized runtime-outcome telemetry, tenant/company hosted persistence, and direct improvement-loop ingestion.
- Added conformance contracts for all 28 provider Tools used by shipped primitives, including live hosted-schema drift detection.
- Added complete behavioral async parity while preserving native async hot paths.
- Added client and MCP entrypoints for executable catalog discovery, SDK execution, project validation, event-routed and durable project operations, outcome flush, connector conformance, and the governed investment-agent facade. The default non-private MCP surface reports 1360 tools (1363 with the private runtime-action opt-in), and the compact Backbone profile reports 88.
- Added CUSTOM_PROJECTS.md with local, hosted, connector, custom primitive, workflow binding, and testing guidance.
0.13.0
- Added a durable tenant/company-scoped workflow-improvement ledger, authenticated outcome ingestion, scoped repositories, and RBAC permissions for read, write, approval, and delivery.
- Added immutable hash-chained implementation/publish/deploy decisions protected from update/delete in Postgres.
- Added SDK, async SDK, CLI, and MCP operations for sync, server status/queue, decisions, audit, delivery start, and delivery evidence. The full surface reports 1278 tools and the compact backbone profile reports 52.
- Added the Harness delivery contract and executor for isolated
codex/branches, implementation checks, draft PRs, CI, disposable staging, bounded canaries, automatic rollback, and cleanup. - Added
communication.classify_replyto the Python and hosted MCP primitive catalogs with privacy-aware telemetry and human-review fallback.
0.12.0
- Added a proposal-only continuous workflow-improvement engine with synthetic evaluation of every primitive, score/trend history, sanitized observed outcomes, queue deduplication, overlap locking, stop-file support, and no-progress tracking.
- Added
lightbulb improve-workflows run|watch|status|queueplus SDK/client APIs. Generated work packets route throughworkflow_authoring, require human implementation approval, and cannot automatically edit, publish, deploy, or invoke connectors. - Added MCP tools
run_workflow_improvement_cycle,get_workflow_improvement_status, andlist_workflow_improvement_packets. The full surface reports 1269 tools and the compact backbone profile reports 43.
0.11.0
- Added an SDK-first custom workflow authoring loop: deterministic primitive recommendation, portable
lightbulb.business_workflow_definition.v1compilation, fail-closed validation, and side-effect-free simulation. - Added
compile_business_workflow,validate_business_workflow, andsimulate_business_workflowto MCP. The full surface now reports 1266 tools and the compact backbone profile reports 40. - Added a harness
workflow_authoringroute and Codex prompt profile that teaches coding agents to extend business primitives in the SDK first, prove compile/validate/simulate behavior, and keep MCP as a thin adapter.
0.10.1
- Documentation refresh for the Lightbulb MCP page and partner docs route, including current
lightbulb-mcpinstall/setup guidance,LIGHTBULB_MCP_PROFILE=backbonedefaults, hosted MCP endpoint notes, and full-vs-namespace-filtered tool-surface guidance. The current full local surface reports 1263 tools vialightbulb tools --count-only; the backbone profile reports 37. - Added
lightbulb versionso partners and support can verify the installed SDK/MCP package without a Python one-liner.
0.8.0
- Full typed coverage for the commerce surface.
lightbulb/tool_descriptors.pynow carries descriptors for every connector op in the commerce domain — Shopify intelligence (shopify.analytics_query,shopify.list_abandoned_checkouts,shopify.list_locations,shopify.list_collections,shopify.list_fulfillment_orders,shopify.list_discounts,shopify.list_refunds,shopify.list_transactions,shopify.bulk_operation_*), metafields (shopify.get_metafields,shopify.update_metafield,shopify.list_metafield_definitions), segment execution (shopify.tag_customers_bulk,shopify.create_price_rule), the storefront-neutralecommerce.*ops (search_products,search_orders,search_customers,get_inventory,get_product_reviews,create_discount,update_customer), and the Square POS ops (search_catalog,search_orders,list_payments,list_customers,get_inventory). MCP consumers — Claude Code, Codex, Cursor — now see proper Python signatures with documented params instead of the genericarguments: str = "{}"JSON blob. - Codegen log:
24 typed via descriptorfor domain actions,53 typed via descriptorfor connector ops (up from 32). Total descriptor surface: 84 (24 domain + 60 connector). - This release pairs with a platform-side rework that exposes each connector op as a top-level OpenAI function tool (encoded
connector__action) inside the commerce domain agent, ending the silentUnknown toolfailures from earlier versions where the prompt advertised dotted op names that the function-call schema couldn't accept.
0.7.0
- Typed signatures + curated descriptions for the highest-value tools. A new
lightbulb/tool_descriptors.pycarries hand-curated metadata (multi-line description + per-field types) for 56 priority tools across finance, CRM, legal, HR, coding, plus the most-used connector ops (Xero, QuickBooks, Stripe, Square, Slack, GitHub, Gmail, Microsoft 365, Notion, Jira, Clio, Shopify). When a descriptor exists, codegen emits a typed Python signature likedef finance_lbo_model(message: str = "", target_company: Optional[str] = None, entry_multiple: Optional[float] = None, …)and a rich docstring; FastMCP picks these up so Claude Code / Codex see proper input schemas instead of an opaqueinputs: strJSON-string parameter. - Tools without a descriptor still generate fine via the original
message + inputs JSONshape — descriptor coverage expands incrementally over future patches without breaking existing flows. - Codegen log:
24 typed via descriptorfor domain actions,32 typed via descriptorfor connector ops. Total surface unchanged at 849 generated + 156 hand-written = 1005 tools.
0.6.2
lightbulb connect <provider>— best-effort CLI to hook up a personal Slack / HubSpot / Notion / Gmail / GitHub / etc. account to the user's tenant. Validates the provider againstlist_connectors(), opens the platform's OAuth flow in a browser.lightbulb connect --check <provider>verifies the connection landed (post-auth confirmation step until the platform supports?return_to=cli).lightbulb tools— list the MCP tool surface this install actually exposes (with namespace-filter awareness).--filter SUBSTRto narrow,--count-onlyfor scripting. Useful for diagnosing which connector ops are reachable when the platform hasn't finished provisioning the full connector tool catalog yet.
0.6.1
- Bug fix: device-flow login surfacing localhost verification URLs. When a platform deployment's base URL is misconfigured, the device-flow verification link could come back pointing at
localhost, producing a confusing "Refusing to open verification URL … does not match platform host" error. The SDK now detects that case and surfaces an actionable hint ("ask your Lightbulb admin to setAPP_BASE_URL") so users know who to contact instead of seeing a bare host-mismatch error. - Regression test:
tests/test_security.py::TestRedirectUrlValidator::test_localhost_mismatch_surfaces_actionable_hint.
0.6.0
- Namespace filtering for the generated tool surface. Set
LIGHTBULB_MCP_NAMESPACES=finance,crm,gmail(or any comma-separated subset) to register only the matching generated tools — typically cuts the cold-starttools/listpayload from ~1005 tools / ~80k tokens to ~200 tools / ~15k tokens. Hand-written tools (whoami, dispatch_domain_agent, etc.) always register. See README "Trimming the tool surface". - Codegen at
scripts/generate_mcp_tools.pynow tags each generated tool with its explicit namespace (e.g.it_ops,document_intelligence) so multi-word namespaces filter correctly without underscore-split ambiguity. - Regression tests for the filter behaviour:
tests/test_mcp_server.py::test_namespace_filter_*.
0.5.1
- Critical: fix
invoke_toolwire shape. Earlier versions sent the wrong request body to/api/tools/invoke, so the 565 generated connector-op tools in 0.5.0 all failed silently. The client now sends thetoolName+inputs(plus tenant/company scope) shape the platform expects. Sync + async clients fixed; regression tests added intests/test_client.py::TestInvokeToolandtests/test_async_client.py::TestAsyncInvokeTool. - Security: collapse inline
is_localchecks inclient.py/async_client.pyonto canonicalvalidators.is_local_url(now covers IPv6::1); add UUID validation inselect_companyMCP tool; assertJwtAuthinsave_cached_token; clarifybackbone_executeruns server-side. - Depends on a platform-side rollout that registers the connector tool catalog; once that rollout is live, the 565 generated connector tools become reachable end-to-end.
0.5.0
- Massive tool surface expansion (~1000 tools, up from 156). Every domain agent action and every registered platform connector op now has a direct MCP tool — Claude Code / Codex / Cursor see them in the picker without indirection.
- 284 domain action tools auto-generated from
agent-workers/agents/domain_registry.py: finance, intuit, crm, legal, engineering, content, it_ops, commerce, product, hr, coding, document_intelligence, solver, customer_success, procurement, gtm, grc, smarthome. - 565 connector op tools auto-generated from the platform's tool registry: deep coverage of Xero (127), Clio (63), GitHub (58), Slack (57), Commerce (51), QuickBooks (44), Smokeball (39), Monday (31), Jira (27), Notion (21), Shopify (18), Stripe, Square, Salesforce, Microsoft, Gmail, and more.
- Codegen lives at
scripts/generate_mcp_tools.py. Re-run after platform changes. - Hand-written 156 tools kept as-is; no API changes there.
0.4.0
- Renamed package to
lightbulb-mcp; MCP deps (mcp,pydantic,pydantic-settings) are now hard dependencies. Python API ships as preview/unstable internals. - Defaults updated to production:
LIGHTBULB_URLdefaults tohttps://agents.lightbulbpartners.com. CLI / MCP server / setup wizard all use the plural production hostname. - Security hardening: redirect URL validation, token/config atomic writes, TOML injection fixes, SSE size limits, localhost detection via hostname parsing, preview proxy header merging.
errorsmodule andraise_if_error: platform HTTP errors map toLightbulbErrorsubclasses from the sync/async clients and Xero wrapper.refresh_auth/ optionalauth_refreshcallback; setup wizard retries once on stale cached token.py.typed+ README/MCP docs consolidation.
0.3.0
- 2FA (
TwoFactorRequired,complete_2fa_login), SSO URL helper, SSE streaming for code/page/document builders, code workspace tools & preview, marketing connector setup methods, typed connector clients,AsyncLightbulbClient,lightbulbCLI, guidedlightbulb setup/lightbulb status,lightbulb-mcpentry point.
0.2.0
- Large MCP tool expansion, domain registry alignment,
XeroAgentClient, expanded platform surface in MCP.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lightbulb_mcp-0.16.0.tar.gz.
File metadata
- Download URL: lightbulb_mcp-0.16.0.tar.gz
- Upload date:
- Size: 4.0 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28a076ccd2bf8fbb062a269c01a194a2d181c378ed39abb35af5001e97a042c4
|
|
| MD5 |
a7bbe1ebb2f86a4cf237edca57d45da2
|
|
| BLAKE2b-256 |
8163c246c1d88b0991ac6101b0a1f0fd44933571f37de91b6139d4e726e2d90a
|
Provenance
The following attestation bundles were made for lightbulb_mcp-0.16.0.tar.gz:
Publisher:
publish-lightbulb-mcp.yml on RPasquale/project401
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lightbulb_mcp-0.16.0.tar.gz -
Subject digest:
28a076ccd2bf8fbb062a269c01a194a2d181c378ed39abb35af5001e97a042c4 - Sigstore transparency entry: 2696216988
- Sigstore integration time:
-
Permalink:
RPasquale/project401@97d90a2fd63a205d9077d337f42d3a6440e5cb91 -
Branch / Tag:
refs/tags/lightbulb-mcp-v0.16.0 - Owner: https://github.com/RPasquale
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-lightbulb-mcp.yml@97d90a2fd63a205d9077d337f42d3a6440e5cb91 -
Trigger Event:
push
-
Statement type:
File details
Details for the file lightbulb_mcp-0.16.0-py3-none-any.whl.
File metadata
- Download URL: lightbulb_mcp-0.16.0-py3-none-any.whl
- Upload date:
- Size: 4.2 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28664236aa28d9eb1d4b8bc0f7245bd93dbb3af665734318ae7d0a9c6ee80174
|
|
| MD5 |
c801356dae847251bee6dd9d8f5c5c0d
|
|
| BLAKE2b-256 |
806bb33a91136907c4e545c4a4bb6834fe5dec3a74a177e6749d40b8568dd240
|
Provenance
The following attestation bundles were made for lightbulb_mcp-0.16.0-py3-none-any.whl:
Publisher:
publish-lightbulb-mcp.yml on RPasquale/project401
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lightbulb_mcp-0.16.0-py3-none-any.whl -
Subject digest:
28664236aa28d9eb1d4b8bc0f7245bd93dbb3af665734318ae7d0a9c6ee80174 - Sigstore transparency entry: 2696217089
- Sigstore integration time:
-
Permalink:
RPasquale/project401@97d90a2fd63a205d9077d337f42d3a6440e5cb91 -
Branch / Tag:
refs/tags/lightbulb-mcp-v0.16.0 - Owner: https://github.com/RPasquale
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-lightbulb-mcp.yml@97d90a2fd63a205d9077d337f42d3a6440e5cb91 -
Trigger Event:
push
-
Statement type: