Skip to main content
An agent working in a workspace can write JavaScript and run it. Those scripts import @arg/sdk, while custom apps use the host-provided @arg-ai/sdk. The run binds every call to the turn’s identity, workspace, read-only state and switches before the script starts. Nothing in the script chooses those, and no long-lived credential is ever inside it.

run_code

run_code executes a JavaScript body in an isolate with no network of its own. Static imports from @arg/sdk and its subpaths are hoisted out of the body; SDK calls cross the run’s dispatcher, which enforces the turn’s gates.
Rules the isolate enforces:
  • Only @arg/sdk may be imported; any other static import is refused with a message the agent can act on, wherever the declaration sits in the body.
  • Each execution gets a fresh binding; cached source can never inherit another turn’s authority.
  • A tool-restricted subagent cannot use the SDK at all, and one script may make at most 100 SDK calls.
  • fs.open, host, db, ui and integrations.proxy need a host the isolate does not have and report unsupported_capability. fs.watch polls metadata while the script runs.

run_bash and arg exec

The sandbox image that runs shell commands carries the @arg/sdk package at its root, so a .mjs file under /ws imports it without installing anything:
/ws/scripts/copy-notes.mjs
run_bash
Every shell command receives a freshly minted capability, scoped to the run’s identity, workspace and read/write gate and expiring within 15 minutes; the SDK picks it up from the injected environment. The account’s own tokens and API keys stay in Arg. Command output and server logs redact the injected values, and a script must never print, persist, copy or transmit the ARG_* variables it finds. Plain shell tools still read and write /ws directly; reach for the SDK when the script also needs Actions, chats, workspace discovery or the normalised API contracts.

What a script may start

A script’s capability follows the turn: The last row is deliberate. A card that approves one command does not approve the chat turns or shell runs a script might start with a token that outlives that command, so those calls are refused with permission_denied unless the user already lets the agent act without a card. The Code and Servers switches on the turn also gate code.run and the servers namespace from a script, exactly as they gate the agent’s own tools.

Reading the results

Scripts see the same receipts as any other client: an Action’s status, a chat send’s call_id, a code.run’s stdout and status. Inspect them; a refused call is an ordinary rejection with an error code from the reference, and the agent should report it rather than retry an accepted write.