Build apps for the Linkworld Open App Platform
Project description
linkworld-sdk
Python SDK for building apps on the Linkworld Open App Platform.
Status: 0.x alpha. Phase 2 of the open-platform rollout. Decorator API is stable; production runtime (MCP-based dispatch) lands with platform Milestone 5. Until then, run apps in local mode to develop against the SDK, then deploy once the platform side is online.
Install
pip install linkworld-sdk
60-second tour
from linkworld_sdk import App
app = App.from_manifest("linkworld.app.yaml")
@app.on_inbound
async def handle(ctx, env):
await ctx.tools.call(
"email_send",
to="ops@example.com",
subject="Inbound!",
body=f"From {env.user_id}: {env.message_text}",
)
if __name__ == "__main__":
app.run()
The matching manifest:
apiVersion: linkworld.ai/v2
app_id: my-app
version: 0.1.0
name: My App
required_scopes: [mail.send]
runtime:
image: ghcr.io/your-org/my-app:0.1.0
lifecycle:
on_inbound: true
Local development
LINKWORLD_LOCAL=1 python main.py
This starts a trigger HTTP server you can curl to simulate any
platform event. Tools are mocked — ctx.tools.call(...) records
the call and returns whatever you wired with MockTools.
See examples/hello-world/ for a runnable
walkthrough.
Testing your app
import pytest
from linkworld_sdk.testing import TestClient
from my_app import app
@pytest.fixture
def client():
return TestClient(app)
async def test_echo(client):
client.tools.set_response("email_send", {"sent": True})
await client.simulate_inbound(
tenant_id="t1", user_id="u1", message_text="hello"
)
assert client.tools.calls[0][0] == "email_send"
assert client.tools.calls[0][1]["body"] == "From u1: hello"
Decorator API
| Decorator | Receives | When |
|---|---|---|
@app.on_inbound |
(ctx, env) |
Tenant got an inbound message and opted into fan-out |
@app.on_install |
(ctx) |
Tenant activated the app |
@app.on_uninstall |
(ctx) |
Tenant deactivated the app |
@app.on_user_added |
(ctx, user) |
New user joined the tenant |
@app.on_schedule(name) |
(ctx) |
Cron entry from lifecycle.schedules[name] fires |
@app.tool(name, ...) |
(ctx, **args) |
Custom tool exposed to tenant agents |
Every handler receives a Context:
ctx.tenant_id # UUID of the tenant
ctx.user_id # UUID of the originating user, or None
ctx.app_id # this app's slug
ctx.event_type # 'inbound', 'schedule', 'install', etc.
ctx.tools # ctx.tools.call("tool_name", **args)
ctx.secrets # await ctx.secrets.get("KEY")
ctx.logger # structlog-compatible logger
Manifest schema
The full schema lives at
packages/sdk-spec/manifest-v2.schema.yaml.
Validate locally with linkworld_sdk.load_manifest("linkworld.app.yaml").
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
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 linkworld_sdk-0.2.0.tar.gz.
File metadata
- Download URL: linkworld_sdk-0.2.0.tar.gz
- Upload date:
- Size: 30.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
138477b5b0df242396e2f48c6265b7d94272af6331687e49ce6be800492dc35f
|
|
| MD5 |
77b63a9b18a3f18b82bc49bd937a922b
|
|
| BLAKE2b-256 |
f72f0cfc86ac4bad91fd6c8e0b31f5f7e8e76d23d0203b939b1f13b6ea0244ac
|
File details
Details for the file linkworld_sdk-0.2.0-py3-none-any.whl.
File metadata
- Download URL: linkworld_sdk-0.2.0-py3-none-any.whl
- Upload date:
- Size: 25.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d82842923557613029be6e4a5691f6c63f91ad2fc88fc02d8c8538c38bd85705
|
|
| MD5 |
5fae89db4aaa1cd4e83e32ce1243b39f
|
|
| BLAKE2b-256 |
e3429d3a7d0ce5def2b11006cd80a903b322e6f7d28af0c2a5a38d5d7a27cc8d
|