Skip to main content
Glama

write_app_files

Write app files into a persistent server-side workspace, then deploy the app; edit later by writing only changed files and redeploying.

Instructions

Write files into an app's server-side workspace, then deploy it.

    The two-step idiom for building an app from this conversation:
    ``write_app_files`` (as many batches as you like) then ``deploy_app``.
    The workspace survives the deploy and IS the working copy, so editing is
    "write the one changed file → ``deploy_app`` again".

    One batch is all-or-nothing: an invalid entry rejects the whole request
    and nothing is written. Binary content is refused — deploy binaries from
    a repo with ``deploy_git``; assets normally come from the build
    (npm/pip). A secret belongs in ``set_secret``, which injects it at launch
    without it ever living in a file. WARNING: file contents you pass here
    transit this agent's transcript in plaintext; never write secrets into
    app files.

    SANDBOX: by DEFAULT containers run with all Linux capabilities dropped
    (``cap_drop=["ALL"]``) and no-new-privileges — both are operator settings
    (``[containers].drop_all_caps`` / ``[containers].no_new_privileges``), so
    read the live profile in ``capabilities.sandbox`` rather than assuming: an
    operator may have relaxed it. Under that default, an image whose entrypoint
    does root work — ``chown``/``chmod`` of its own runtime dirs, dropping
    privileges via ``setuid``/``setgid``, writing ``/var/run`` — dies before
    your app ever starts. Stock ``nginx`` is the classic trap. Use a non-root
    image and a non-root ``USER`` that owns the files it writes: for a static
    site, ``nginxinc/nginx-unprivileged`` (listens on **8080**, so set
    ``port=8080``) or any tiny static server. A crash from this reports
    remediation code ``image_needs_privileges`` in ``diagnose_service``. PORT
    CONTRACT: the container MUST listen on the declared ``port`` (the tool
    argument, else ``nerdit.toml`` ``[deploy].port``, else **8000**) — that is
    the only port the daemon publishes and health-checks, so listening anywhere
    else fails the health probe with a healthy-looking container. A port below
    1024 is NOT the reason a root entrypoint is needed: every container runs on
    the docker bridge in its own network namespace (never host networking),
    where Docker sets ``net.ipv4.ip_unprivileged_port_start=0``, so binding 80
    needs no capability and no root — the chown/setuid work does.
    

Input Schema

NameRequiredDescriptionDefault
nameYesWorkspace name, a DNS label (lowercase a-z0-9 and ``-``, 1-63 chars). A new name creates the workspace; an existing one is edited in place. It is also the app name ``deploy_app`` deploys it under.
filesYesWorkspace-relative path -> that file's full UTF-8 text; a write replaces the file whole. Paths are relative with no ``..``; ``.git``, ``node_modules``, ``__pycache__``, ``.venv``, ``data/`` and ``*.pyc`` are refused, and ``.env`` / ``.env.*`` by name. Text only (NUL or non-UTF-8 is refused). Caps: 256 KiB per file, 10 MiB and 500 files per workspace.
deleteNoWorkspace-relative paths to remove, applied with the writes in the same all-or-nothing batch. Omit (null) to delete nothing; a path that does not exist is a no-op; a path may not be in both ``files`` and ``delete``.
idempotency_keyNoCaller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts.

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observedv0.1.0

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: all-or-nothing batch semantics, binary refusal, the plaintext-transcript warning for file contents, default sandbox capability drops with the image_needs_privileges remediation code, and the port contract with its precedence chain. These are non-obvious failure modes an agent would otherwise hit blind.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core idiom before the caveats, and the WARNING/SANDBOX/PORT CONTRACT labels make it scannable. It is long, and the port-below-1024 aside is more explanation than an agent needs to select the tool, but nearly every sentence carries actionable content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

A mutation tool with zero annotation coverage and no output schema would normally be a big gap, but the description supplies batch atomicity, size/path constraints context, secret-handling policy, sandbox failure modes, and port requirements. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so name, files, delete, and idempotency_key are already fully documented. The description adds only the port precedence rule (tool argument → nerdit.toml → 8000), which is useful but belongs to deploy_app rather than this schema. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Write files into an app's server-side workspace, then deploy it') and immediately differentiates itself from siblings: deploy_git for binaries, set_secret for secrets, deploy_app as the follow-up step. An agent can place this tool precisely among the deploy/serve/apply family without opening another schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit two-step idiom (write_app_files in batches, then deploy_app) and the iterative editing pattern ('write the one changed file → deploy_app again'). It also names the alternative tool for each excluded case: deploy_git for binary content, set_secret for credentials, build tooling for assets.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.