Install
openclaw skills install launchthatbot-importExport your OpenClaw agent config, memory, skills, and encrypted secrets to a LaunchThatBot deployment. One-time, end-to-end encrypted transfer -- LaunchThatBot never sees your raw API keys.
openclaw skills install launchthatbot-importThis skill lets you export your current OpenClaw agent configuration to a LaunchThatBot.com deployment. Your secrets (API keys, tokens) are encrypted before leaving this machine and are decrypted only inside your new container. LaunchThatBot never has access to the raw values.
This skill supports two import modes:
import_handshake (via mcporter) to fetch the RSA public key.import_push directly to LaunchThatBot API.In both modes, token/session is one-time + short-lived and the target container is restarted after import.
This skill is built around the question: "Why would I share my API keys with a platform I have never heard of?"
The answer: you are not sharing them with us.
.env file on your VPS. If you use the launchthatbot/convex-backend skill, secrets are stored in your connected Convex instance instead of directly in each new agent's .env. You can verify via SSH for .env-based setups or in your Convex dashboard/instance for Convex-backed setups.When the user says something like "export my config to LaunchThatBot" or "migrate to LaunchThatBot", follow these steps:
This skill is mcporter-first for OpenClaw/Pi compatibility.
Before running this flow, verify prerequisites in this order:
mcporter is runnable:mcporter --version || npx -y mcporter --version
If this fails, tell the user:
mcporter is required for this skill. Please enable npx mcporter (or install/configure mcporter), then run import again."(mcporter list || npx -y mcporter list)
(mcporter list launchthatbot --schema || npx -y mcporter list launchthatbot --schema)
If launchthatbot is not available, attempt automated setup (if environment allows) and then re-check. If automation is blocked, ask the user to configure LaunchThatBot MCP manually.
Recommended MCP config:
{
"mcpServers": {
"launchthatbot": {
"command": "npx",
"args": ["-y", "@launchthatbot/mcp-server"]
}
}
}
(mcporter list launchthatbot --schema || npx -y mcporter list launchthatbot --schema)
Confirm import_handshake and import_push exist.
Ask the user for:
https://api.ltb.it.com)The user gets the import token by clicking Import Agent on their agent's detail page in the LaunchThatBot dashboard.
Call LaunchThatBot MCP through mcporter:
npx -y mcporter call launchthatbot.import_handshake \
importToken:"<importToken>" \
apiUrl:"https://api.ltb.it.com"
Response:
{
"publicKey": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
"agentName": "My Agent",
"expiresAt": 1708000000000
}
If the response is a 401, the token is invalid, expired, or already used. Ask the user to generate a new one.
If the user chooses air-gapped mode, read the session file provided by LaunchThatBot dashboard and extract:
importTokenpublicKeyexpiresAtapiUrlDo not call import_handshake in air-gapped mode if the session file already includes a valid publicKey.
Gather the following from the local filesystem:
soul.md (agent personality/instructions):
/home/node/.openclaw/config/agents/*/soul.mdMemory files:
/home/node/.openclaw/memory/.md and .json filesSkills:
/home/node/.openclaw/skills/launchthatbot-import) from the exportEnvironment secrets (.env file):
/home/node/.openclaw/.envKEY=VALUE lineBefore sending anything, show the user a summary:
Ask the user to confirm they want to proceed.
For each secret from the .env file, encrypt the VALUE using the RSA public key fetched from the handshake endpoint. Use RSA-OAEP with SHA-256 padding.
const crypto = require("crypto");
function encryptSecret(value, publicKeyPem) {
const encrypted = crypto.publicEncrypt(
{
key: publicKeyPem,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: "sha256",
},
Buffer.from(value, "utf8"),
);
return encrypted.toString("base64");
}
If encryption fails, verify the public key is a valid PEM string starting with -----BEGIN PUBLIC KEY-----.
Send everything via LaunchThatBot MCP through mcporter:
npx -y mcporter call launchthatbot.import_push --args '{
"importToken": "<importToken>",
"apiUrl": "https://api.ltb.it.com",
"payload": {
"config": {
"soulMd": "<contents of soul.md>",
"memory": [
{ "filename": "MEMORY.md", "content": "<file contents>" },
{ "filename": "daily-log.json", "content": "<file contents>" }
],
"skills": [
{ "path": "web-search/SKILL.md", "content": "<file contents>" },
{ "path": "email-sender/SKILL.md", "content": "<file contents>" }
]
},
"encryptedSecrets": [
{ "key": "OPENAI_API_KEY", "ciphertextB64": "<base64 encrypted value>" },
{ "key": "ANTHROPIC_API_KEY", "ciphertextB64": "<base64 encrypted value>" }
]
}
}'
If successful, tell the user:
If it fails, report the error and suggest generating a new import token from the LaunchThatBot dashboard.
If the user selected air-gapped mode, do not push to API from the old instance. Instead, write a local bundle file for the user:
{
"schema": "ltb-airgap-import@1",
"importToken": "<importToken>",
"apiUrl": "https://api.ltb.it.com",
"payload": {
"config": {
"soulMd": "...",
"memory": [{ "filename": "MEMORY.md", "content": "..." }],
"skills": [{ "path": "web-search/SKILL.md", "content": "..." }]
},
"encryptedSecrets": [{ "key": "OPENAI_API_KEY", "ciphertextB64": "<...>" }]
}
}
Tell the user to upload this bundle in LaunchThatBot:
Do NOT include in the export:
launchthatbot-import/)convex-backend skill (it will be re-provisioned by LaunchThatBot).git directoriesnode_modules directoriespackage-lock.json, pnpm-lock.yaml, etc.)| Error | What to Do |
|---|---|
| 401 Unauthorized | Token is invalid, expired, or already used. Generate a new one from the LaunchThatBot dashboard. |
| 400 Bad Request | Check the payload format matches the schema above. |
| 500 Internal Server Error | Server-side issue. Wait a moment and try again, or contact support on the LaunchThatBot Discord. |
| Network error | Check internet connectivity. Verify the API URL is correct (default: https://api.ltb.it.com). |