Files
LangBot/skills/skills/langbot-testing/references/sandbox-skill-authoring.md
T
Junyan Chin e9dd584792 feat: MCP server + in-repo skills (agent-friendly platform) (#2269)
* feat(api): support global API key from config.yaml (api.global_api_key)

Accept a config-defined global API key anywhere a web-UI key is accepted
(X-API-Key / Bearer), with no login session and no DB record. Useful for
automated deployments and AI agents (HTTP API + MCP). Defaults to empty
(disabled); does not require the lbk_ prefix.

- templates/config.yaml: add api.global_api_key with security notes
- service/apikey.py: verify_api_key checks global key first (constant-time)
- docs/API_KEY_AUTH.md: document the global key + security guidance
- tests: cover global-key match, prefix-free, fallback-to-db, disabled

* feat(mcp): expose LangBot management as an MCP server at /mcp

Add an MCP (Model Context Protocol) server so external AI agents can manage a
LangBot instance. Reuses the same API-key auth as the HTTP API (including the
config.yaml global API key).

- pkg/api/mcp/server.py: FastMCP server wrapping the service layer; 21 curated
  tools across system/bots/pipelines/models/knowledge/mcp-servers/skills
- pkg/api/mcp/mount.py: ASGI dispatcher fronting Quart; authenticates /mcp
  requests with an API key, runs the streamable-HTTP session manager lifespan
- controller/main.py: serve the wrapped ASGI app via hypercorn (was run_task)
- web: new 'MCP' tab in the API integration dialog showing endpoint, auth, and
  client config; i18n for 8 locales
- tests/manual/mcp_smoke.py: e2e check (401 unauth, list tools, call tools)

Tool surface is intentionally curated (not all ~25 route groups) to keep the
agent surface small, safe, and maintainable. Extend deliberately.

* feat(skills): add in-repo skills/ as the single source of truth

Migrate the agent skills + QA/e2e test harness from the (now archived)
langbot-app/langbot-skills repo into LangBot/skills/, and add four new skills.

Migrated:
- langbot-plugin-dev, langbot-testing (e2e), langbot-env-setup,
  langbot-skills-maintenance, langbot-eba-adapter-dev
- the bin/lbs CLI (src/, test/, scripts/, schemas/, qa-agent-docs/)

New:
- langbot-dev      core backend + web development
- langbot-deploy   Docker/K8s deployment + config.yaml + global API key
- langbot-mcp-ops  operating the LangBot MCP server (/mcp)
- langbot-space-ops operating the Space marketplace MCP server

- src/cli.ts repoRoot(): recognize the skills assets root (skills.index.json +
  bin/lbs) so the CLI works when nested inside the LangBot repo
- README.md: unified skill catalog; skills.index.json regenerated

Parity with source verified: bin/lbs validate + node test suite match the
source repo (only the uncommitted .lbpkg build-artifact fixture differs).

* docs(agents): document agent-facing surfaces + API/MCP/skills sync rule

* docs(readme): add 'Built for AI Agents' section across all locales

Highlight MCP server, in-repo skills (single source of truth), AGENTS.md
sync rule, and llms.txt. Cross-link LangBot Space MCP marketplace.

* style(mcp): fix ruff format + prettier lint in MCP server and API panel

* style(web): prettier format MCP i18n locale entries

* docs(skills): note MCP instance control in dev/testing skills

All development-guidance skills now point to the LangBot instance MCP
server (/mcp) and the Space marketplace MCP server, reusing API keys.
2026-06-20 15:14:47 +08:00

5.4 KiB

Sandbox Skill Authoring

Goal

Verify that Local Agent can use sandbox tools to create, register, activate, and use a LangBot skill package through the same path a user would exercise in Debug Chat.

This flow applies to Docker, nsjail, and E2B backends. API calls are useful diagnostics, but the primary pass/fail signal is the model-driven Debug Chat tool sequence.

Preconditions

  1. Read ../.env and use LANGBOT_FRONTEND_URL and LANGBOT_BACKEND_URL.
  2. Start LangBot with the intended backend:
    • BOX_BACKEND=e2b when validating E2B.
    • BOX_BACKEND=nsjail when validating nsjail.
    • BOX_BACKEND=local or docker when validating local container fallback.
  3. Confirm /api/v1/box/status reports available: true and the expected backend name.
  4. Confirm Debug Chat uses a model with function-calling ability.
  5. Confirm backend logs say native sandbox tools are available.

Do not store sandbox provider keys, JWTs, OAuth tokens, or localStorage values in the case or notes.

Debug Chat Prompt Pattern

Use a unique skill name per run, for example:

lb-sandbox-agent-e2e-<timestamp>

Send a prompt that requires the model to do all of the following:

  1. Use exec to create a multi-file skill under /workspace/<skill-name>.

  2. Include at least:

    • SKILL.md
    • scripts/use.py
    • data/input.json
  3. In the same first exec, run the script and verify a deterministic marker such as:

    SANDBOX_COMPLEX_SKILL_OK sum=10 product=24
    
  4. Call register_skill with path=/workspace/<skill-name>.

  5. Call activate with skill_name=<skill-name>.

  6. Call exec with workdir=/workspace/.skills/<skill-name> and run:

    python3 scripts/use.py && echo SANDBOX_ACTIVATED_WRITEBACK_OK > activated_writeback.txt && cat activated_writeback.txt
    
  7. Require the final answer to contain only an explicit success marker:

    E2E_OK:<skill-name>
    

Keep the test script robust to working-directory changes. Prefer resolving data paths from __file__:

from pathlib import Path
data_path = Path(__file__).resolve().parent.parent / "data" / "input.json"

Success Criteria

The UI should show an assistant final response containing E2E_OK:<skill-name>.

Backend logs should show:

  • exec tool invoked
  • register_skill
  • activate
  • a second exec whose workdir is /workspace/.skills/<skill-name>
  • backend=e2b, backend=nsjail, or the expected local backend

After the run, verify the skill store through the UI or API:

  • Skill root lists SKILL.md, scripts, data, and activated_writeback.txt.
  • scripts/use.py is readable.
  • data/input.json is readable.
  • activated_writeback.txt contains SANDBOX_ACTIVATED_WRITEBACK_OK.
  • /api/v1/box/errors is empty.

Existing Skill Edit Variant

The base sandbox-skill-authoring-e2e case only proves create, register, activate, and use. To prove that an already activated skill can be modified, run sandbox-skill-authoring-edit-existing-e2e or use its prompt pattern.

The edit variant must include these additional checks:

  • The second exec uses workdir=/workspace/.skills/<skill-name>.

  • The second exec overwrites SKILL.md, data/input.json, and scripts/use.py under the activated skill path.

  • The modified script prints a deterministic marker such as:

    SANDBOX_SKILL_MODIFIED_OK sum=11 product=56 marker=<updated-marker>
    
  • grep -q <updated-marker> SKILL.md scripts/use.py data/input.json succeeds in the same activated-path command.

  • Filesystem evidence under the Box-managed skill store shows the updated marker, not only the original create marker.

If the model stops after activation and only reruns the original script, treat that run as a failed edit-existing E2E even when create/register/activate succeeded.

Diagnostic Checks

Use these only after the model-driven Debug Chat flow fails:

  • /api/v1/box/status to confirm backend selection and recent errors.
  • /api/v1/box/sessions to check leaked or conflicting sessions.
  • Direct backend probes to separate provider credentials from LangBot integration.
  • Filesystem inspection under the configured Box-managed skill store.

For E2B raw HTTP diagnostics, include a valid template id such as base; a missing template can produce schema validation errors that are unrelated to authentication.

Known Pitfalls

  • When Box is available, skills may be owned by the Box runtime and stored in Box-managed skill storage. Do not assume data/skills is the active source of truth.
  • Public E2B does not provide local bind mounts. Main workspace and activated skill extra mounts must be synchronized into and back out of the E2B sandbox.
  • Session metadata should keep LangBot logical paths such as /workspace; storing provider-internal paths can make later requests look incompatible.
  • nsjail versions differ. Some expose only --disable_clone_new* flags and use --bindmount instead of --rw_bind.
  • On WSL, cgroup v2 may exist but not be writable. The backend should warn and fall back to rlimits rather than fail the sandbox.
  • If ALL_PROXY uses a SOCKS URL and socksio is not installed, some Python HTTP clients can fail during startup. Prefer consistent HTTP proxy variables unless SOCKS support is installed.
  • sandbox-native-tools-unavailable
  • e2b-extra-mount-sync-missing
  • box-session-conflict-logical-metadata
  • nsjail-cli-compatibility
  • socks-proxy-without-socksio