| name | build-script |
| description | Use when the user wants to write, test, or deploy an ArchAstro script — custom logic for agent tools, workflow nodes, and routines. Trigger phrases include "build a script", "write a script", "create a script", "test a script", "script syntax", "script reference", "script language". |
| allowed-tools | ["Bash(archagent:*)"] |
ArchAstro Script Builder
Write, test, and deploy scripts — custom logic that powers agent tools, workflow nodes, and routines.
This skill assumes the ArchAgent CLI is already installed and authenticated. Install or upgrade archagent if missing, and run archagent auth login <email> if not authenticated.
What is a Script?
Scripts are expression-oriented custom logic written in the ArchAstro script language. They can be used as:
- Custom tool handlers: Agent calls a tool → script runs → result returned to agent
- Workflow graph script steps: Script logic used inside a workflow graph
- Routine handlers: A scheduled routine runs the script directly
Scripts are first-class resources with their own CRUD, validation, and execution commands.
Use the dedicated top-level script resource for the normal authoring loop: archagent list scripts, describe script, create script, update script, validate script, run script, and describe scriptdocs.
Always Start with State
Every invocation must begin by understanding the current context:
archagent auth status
archagent list scripts
Determine:
- Is the user creating a new script or editing an existing one?
- What will this script be used for? (tool, workflow node, routine)
- What external APIs or data does it need to access?
Routing
User wants to write a new script
Phase 1: Get the language reference
Always start by fetching the live reference — do not write scripts from memory:
archagent describe scriptdocs
Use the top-level script commands, not describe configsample/validate config, for the normal authoring loop.
Create a script from a local source file:
archagent create script --id my-script --file ./scripts/my-script.agentscript
Or let the CLI start from its built-in sample if you do not pass --source or --file:
archagent create script --id my-script
Phase 2: Understand the requirements
Ask the user:
- What should the script do?
- What inputs will it receive? (accessible via
$ JSONPath)
- Does it need environment variables? (accessible via
env.KEY)
- Does it need to make HTTP calls?
If the script will handle a routine event, discover what $ contains by checking the event's payload schema:
archagent list events
archagent describe event <event-name>
describe event returns the JSON schema and a sample payload. Every field in the payload is accessible via $ in the script (e.g., $.thread_id, $.message.content). Always check the event schema before writing scripts that consume routine payloads — do not guess the shape from memory.
Phase 3: Author the script
Key language concepts:
- Input: Access via
$ (JSONPath). E.g., $.order_id, $.user.email
- Environment: Access via
env.KEY. E.g., env.API_TOKEN
- Imports:
import("requests"), import("array"), import("string"), etc.
- Error handling:
unwrap(result) or unwrap(result, default_value)
- No loops: Use
array.map, array.filter, array.reduce
- Expression-oriented: The last expression in the script is the return value
- Debugging: Use
println() to inspect values
Chain-step context: When a script runs as a step inside a chain routine
(handler_type: chain), its input is wrapped. The triggering event is at
$.trigger.<field> and prior-step outputs are at $.inputs.<step_name>
— not at $.<field> directly. For single-handler script routines the input
is the raw event payload as usual. Name each step you want to reference
from downstream steps; unnamed steps are not addressable by name.
Example — HTTP lookup script:
let http = import("requests")
let arr = import("array")
let response = http.get(env.API_URL + "/orders/" + $.order_id, {
headers: { "Authorization": "Bearer " + env.API_TOKEN }
})
let body = unwrap(response)
{
order_id: $.order_id,
status: body.status,
items: arr.map(body.line_items, fn(item) {
{ name: item.name, qty: item.quantity }
})
}
Available namespaces:
requests — HTTP client (get, post, put, patch, delete)
array — Collection operations (map, filter, reduce, find, sort, flat_map)
string — String operations (split, join, trim, lowercase, uppercase, contains)
map — Object operations (keys, values, merge, get)
datetime — Date/time operations (now, format, parse, add)
math — Math operations (round, floor, ceil, abs)
result — Result type operations (ok, err, is_ok, is_err)
email — Email sending
jwt — JWT token operations
slack — Slack API operations
Phase 4: Validate
Validate the script syntax:
archagent validate script --file ./scripts/my-script.agentscript
Or validate as a config:
archagent validate config -k Script -f ./configs/scripts/my-script.yaml
Fix any validation errors before proceeding.
Phase 5: Test
Run the script locally with test input:
archagent run script --file ./scripts/my-script.agentscript --input '{"order_id": "ORD-123"}'
For scripts that need env vars, ensure they are set on the platform:
archagent list orgenvvars
archagent create orgenvvar -k API_TOKEN -v "sk-..."
Phase 6: Deploy
Scripts can be deployed two ways:
As a standalone script resource:
archagent create script --id order-lookup -n "Order Lookup" --file ./scripts/my-script.agentscript
Update an existing script resource:
archagent update script order-lookup --file ./scripts/my-script.agentscript
Via deploy configs (for config-managed repos):
Place .agentscript files in configs/scripts/ and deploy:
archagent deploy configs
The scripts/ directory enforces that only .agentscript files and .yaml/.json with kind: Script are allowed — other file types are rejected. See the manage-configs skill for setting up the configs directory.
Phase 7: Wire it up
Connect the script to where it will be used:
As a custom tool on an agent:
The API requires --config-id pointing at the script's config ID even for script-handler tools:
archagent create agenttool --agent <agent-id> \
--kind custom \
--name "lookup_order" \
--description "Look up an order by ID" \
--handler-type script \
--config-id <script-config-id> \
--instruction "Use this tool when the user asks to look up an order." \
--parameters '{"type":"object","properties":{"order_id":{"type":"string"}},"required":["order_id"]}'
Get the script's config ID from archagent describe script <id> --output json (the configId field).
In a workflow graph: Follow the real WorkflowGraph shape from archagent describe workflowdocs and the build-workflow skill.
As a routine handler (reference by config ID — preferred for production):
archagent create agentroutine --agent <agent-id> \
--name "My scheduled script" \
--event-type schedule.cron \
--schedule "0 9 * * 1-5" \
--handler-type script \
--config-id <script-config-id>
Get the script's config ID from archagent describe script <id> --output json (the configId field).
Or inline for quick prototyping:
archagent create agentroutine --agent <agent-id> \
--name "Quick test" \
--event-type schedule.cron \
--schedule "0 9 * * 1-5" \
--handler-type script \
--script 'println("hello")'
Prefer --config-id for production — it keeps the routine linked to a versioned script resource that can be updated independently.
User wants to edit an existing script
-
Inspect the current script:
archagent list scripts
archagent describe script <id>
-
Edit locally, validate, and update:
archagent validate script --file ./scripts/my-script.agentscript
archagent update script <id> --file ./scripts/my-script.agentscript
Common Mistakes
Do not write JSON — use script object syntax:
// WRONG — JSON syntax causes "unexpected token :" errors
{ "status": "ok", "count": 5 }
// CORRECT — script uses unquoted keys
{ status: "ok", count: 5 }
Do not use return — the last expression is the return value:
// WRONG
return { status: "ok" }
// CORRECT
{ status: "ok" }
Always import namespaces before using them:
// WRONG — "Unknown identifier" error
let now = datetime.now()
// CORRECT
let dt = import("datetime")
let now = dt.now()
No imperative loops — use array functions:
// WRONG — for/while don't exist
for item in items { ... }
// CORRECT
let arr = import("array")
arr.map(items, fn(item) { ... })
Script Authoring Rules
- Always fetch
archagent describe scriptdocs before writing scripts. Do not invent syntax from memory.
- Prefer the dedicated top-level script commands over the generic
configs resource unless the user explicitly wants config-managed files.
- Treat the language as functional and expression-oriented, not imperative.
- The last expression is the return value — there is no
return keyword.
- Use
unwrap() for error handling — never assume HTTP calls succeed.
- Use
println() liberally while debugging, remove before deploying.
- If validation fails, rewrite toward the sample/reference instead of trial-and-error.
Recovery Rules
- If a script fails validation, show the exact error. Common issues: missing imports, wrong function signatures, trying to use imperative loops.
- If
archagent run script fails at runtime, check: are env vars set? Is the input JSON valid? Is the API reachable?
- If the user is unsure about syntax, always fall back to
archagent describe scriptdocs.
Response Rules
- Do not inspect or edit credential files directly — use the CLI only.
- Do not ask the user to pick raw subcommands when intent is clear.
- Keep responses concise and operational.
- Show the user a concrete script draft they can review, not abstract syntax explanations.