Skip to content

bug: deploy_local_agent (no GitHub repo) silently creates empty agents — fallback path writes outside host-mapped volume #950

Description

@vybe

Summary

mcp__trinity__deploy_local_agent (POST /api/agents/deploy-local) — the archive-based deploy path used by the /trinity:onboard skill from the abilityai/abilities marketplace — is unreliable when the agent has no GitHub repository. Deployments either fail outright or succeed but produce empty agents (container starts with no template files, no CLAUDE.md, no skills).

Root cause

In src/backend/services/agent_service/deploy.py (the templates_dir writability probe at the "Copy to templates directory" step), the writability check on /agent-configs/templates always fails because that mount is bind-mounted read-only in both docker-compose.yml and docker-compose.prod.yml:

- ./config/agent-templates:/agent-configs/templates:ro

The probe catches the OSError and falls back to:

templates_dir = Path("./config/agent-templates")

./config/agent-templates is relative to the backend container's WORKDIR (/app) — it resolves to /app/config/agent-templates/<version-name>, which is not host-mapped. The extracted template lives only inside the backend container filesystem.

When create_agent_internal (in src/backend/services/agent_service/crud.py, elif config.template.startswith("local:") branches around the template_volume setup) then tries to bind-mount the template into the new agent container, it does two things, both broken:

  1. Checks if template_path_in_backend.exists() against /agent-configs/templates/<name> — the read-only mount where the template was not written. Existence returns False, so template_volume stays None and the new agent container is created without the template mounted at /template → empty workspace, "empty agents" failure mode.
  2. If the directory happens to exist (race / stale state), the bind source path is computed from HOST_TEMPLATES_PATH (${PWD}/config/agent-templates/<name>), which doesn't exist on the host → Docker volume mount fails → "deploy fails" failure mode.

Net effect: the documented /trinity:onboard flow for archive-based deploy is broken on every standard deployment (dev + prod compose files both mark the templates dir :ro).

How to reproduce

  1. From a Claude Code agent without an associated GitHub repo, install the public marketplace plugin:
    /plugin marketplace add abilityai/abilities
    /plugin install trinity@abilityai
    
  2. Run /trinity:onboard and choose "Deploy to Trinity".
  3. The skill packages the local directory as a base64 tar.gz and calls mcp__trinity__deploy_local_agent.
  4. Observe either a hard failure or a "success" response where the new agent's /api/agents/{name}/files listing shows no template content (no CLAUDE.md, no template.yaml, no .claude/skills/).

Acceptance criteria

  • POST /api/agents/deploy-local reliably extracts the archive to a host-mapped location (or another path that the new agent's bind-mount will actually see)
  • The fallback path no longer silently writes to a container-only directory; either it writes somewhere the new agent will read, or it fails fast with a clear error code
  • After a successful mcp__trinity__deploy_local_agent response, the new agent's workspace contains template.yaml, CLAUDE.md, .claude/skills/, and any other files from the archive
  • Repeated /trinity:onboard runs against the same agent name produce the expected versioned redeploy (<base>-2, etc.) with full content, not empty workspaces
  • An integration test covers archive → deploy → verify-content on a clean Trinity instance using the stock docker-compose.yml
  • Regression test added for the writable-templates-dir resolution so the read-only mount fallback can't silently degrade again

Technical notes

  • Related code:
    • src/backend/services/agent_service/deploy.pydeploy_local_agent_logic, templates-dir writability probe, template copy step
    • src/backend/services/agent_service/crud.pylocal:-prefixed template resolution, template_volume construction
    • src/backend/services/template_service.pyis_trinity_compatible (CLAUDE.md is a warning, not an error; an archive missing it still passes validation)
    • docker-compose.yml and docker-compose.prod.yml./config/agent-templates:/agent-configs/templates:ro (read-only mount that makes the writability probe always fall back)
    • src/mcp-server/src/tools/agents.tsdeployLocalAgent MCP tool
    • /trinity:onboard skill (SKILL.md v4.7) in abilityai/abilities — calls mcp__trinity__deploy_local_agent and writes .trinity-remote.yaml
  • Related issue: SEC: POST /api/agents/deploy-local bypasses creator role check — any authenticated user can spawn agents (AISEC-H1) #592 (security gap on the same endpoint — role gating)
  • Suggested fix direction: make /agent-configs/templates writable (either drop :ro in compose, or mount a dedicated writable subdirectory for deployed-local templates while keeping the curated catalog read-only), and harden the fallback to fail loudly instead of writing into the container FS
  • Consider tightening is_trinity_compatible so deploys missing CLAUDE.md or expected agent structure either fail or produce a structured warning surfaced in the deploy response, so users notice empty agents at deploy time instead of first interaction

Metadata

Metadata

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions