examples/python-sdk/ara_sdk/modal_like.pyexamples/python-sdk/ara_sdk/__init__.pyexamples/python-sdk/ara(script runner wrapper)
/sdk/quickstart for first-run commands. Use this page when you need exact behavior and edge-case semantics.
Exported surface (ara_sdk)
Default constants
The SDK currently hard-codes these defaults:DEFAULT_SUBAGENT_MAX_CONCURRENCY = 4DEFAULT_SUBAGENT_TIMEOUT_SECONDS = 120DEFAULT_SUBAGENT_MAX_RETRIES = 2DEFAULT_SUBAGENT_RETRY_BACKOFF_SECONDS = 5DEFAULT_API_BASE_URL(production Ara API)
Manifest model
App.manifest resolves to:
- In
App(...):project_name -> slug -> name - Normalized with lowercase + non
[a-z0-9-]collapsed to- - Empty
nameraisesValueError; slug normalization may fall back to"workflow"when the slug source has no valid characters
define_app(...) also accepts dict manifests and enforces:
- dict input
- non-empty
name - derivable
slugfromslug|project_name|project|name
App constructor and state
_agent_profiles: explicit or generated profile declarations_subagent_specs: subagent metadata emitted intoagent.subagents_workflows: task/run/pipeline/hook workflows_local_entrypoint: optional local function forlocalcommand
Decorators: detailed behavior
@app.agent(...)
Registers a profile in agent.profiles and supports:
id,instructions,handoff_to,always_on
- If
idomitted, derives from function name instructionsfalls back to docstring- Stores both
instructionsand backward-compatiblepersona - Upserts by profile
id
@app.subagent(...)
High-level macro that does all of this in one call:
- Creates/updates an agent profile (
@app.agent(...)internally) - Creates a primary workflow (
@app.task(...)internally) - Injects shared-sandbox guardrail text into task instructions
- Stores subagent metadata in
agent.subagents - Expands
hooks=[subagent_hook(...)]into additional workflows
id,workflow_idinstructions,handoff_to,always_ontask,trigger,scheduleadapter,runtime,sandbox,channelshooks
workflow_id: defaults toidruntime.working_dir: defaults tosubagents/<subagent-id>runtime.timeout_seconds: default120runtime.max_retries: default2runtime.retry_backoff_seconds: default5sandbox.policy: default"shared"sandbox.max_concurrency: default4
- Missing hook
idbecomes<workflow-id>-hook-<n> - Missing hook
eventbecomeshook.tick - Missing hook task/command gets default task text
- Hook command mode is wrapped in a shell guardrail launcher
@app.hook(...)
Defines visible hook workflows for schedule/event handling.
Args:
id,event,agent- either
taskorcommand(mutually exclusive) trigger,schedule
- If
commandis set: emits a run-mode workflow via@app.run(...) - Else: emits a task-mode workflow via
@app.task(...)
__ara_hook__.
@app.task(...)
Alias for @app.workflow(mode="task", ...).
@app.run(...)
Alias for @app.workflow(mode="run", ...).
Run-mode constraints:
commandis requiredagent=is rejected in run mode with aValueError
@app.pipeline(...)
Alias for @app.workflow(mode="pipeline", ...).
@app.workflow(...)
Unified primitive behind task/run/pipeline.
Key normalization:
- Workflow ID is slugified
- Trigger is normalized through
_normalize_trigger(...) - Cron schedule can come from
schedule=ortriggercontent - Empty cron expressions fall back to API trigger; cron syntax itself is not validated by the SDK
@app.local_entrypoint()
Registers one local callable used by python app.py local.
call_local_entrypoint(...) invocation rules:
- 0 args function -> called with no args
- 1 arg function -> receives full input dict
- N args function -> kwargs filtered by matching input keys
Guardrail command wrapper behavior
For hook command execution, SDK wraps your command withbash -lc script logic that:
- creates/chdirs to namespaced workdir
- sets or derives
RUN_ID - sets or derives
IDEMPOTENCY_KEY - exports runtime metadata env vars
- emits structured JSON logs for start/done phases
ARA_APP_SLUGARA_SUBAGENT_IDARA_WORKFLOW_IDARA_RUN_IDARA_IDEMPOTENCY_KEYARA_TIMEOUT_SECONDSARA_MAX_RETRIESARA_RETRY_BACKOFF_SECONDS
Helper functions
cron(expression, timezone="UTC")
- validates non-empty expression
- returns
{type:"cron", cron, schedule, timezone}
sandbox(...)
- Only shared mode is enabled
- Passing policy other than
"shared"raisesValueError
subagent_hook(...)
Builds dict hook specs for @app.subagent(..., hooks=[...]).
Validation:
eventrequiredtaskandcommandare mutually exclusive
event_envelope(...)
Builds normalized event payload:
file(...) / local_file(...)
file(...)creates runtime file declarationslocal_file(...)reads local disk content and maps target pathlocal_file(...)defaultsexecutable=True- missing source file raises
ValueError
runtime(...)
Runtime-profile builder with pass-through filtering for:
- image/memory/volume
- python/node packages
- files/startup
- adapter/artifacts
entrypoint(path, shell="bash", args=None)
- validates non-empty path
- returns startup descriptor for
runtime_profile.startup
Adapter + artifact helpers
command_adapter(...) fields:
type: "command"framework,transport,entrypoint,args- optional
artifact,env
langchain_adapter(...)addsAGENT_FRAMEWORK=langchainlanggraph_adapter(...)addsAGENT_FRAMEWORK=langgraphagno_adapter(...)addsAGENT_FRAMEWORK=agno
git_artifact(repo_url, ref="main", subdir="")tarball_artifact(url, strip_prefix="")
Runtime client (AraApp)
AraApp is the imperative API wrapper used by CLI commands.
Construction
- reads
.envincwd - only sets env vars that are currently unset
- defaults API base to production when unset
- requires
ARA_ACCESS_TOKEN
App lookup semantics
_find_app_by_slug() does:
GET /apps- matches by
manifest.slug - returns only owner role app rows (member apps ignored)
deploy(...)
- existing app:
on_existing=error-> raisesRuntimeError- else updates via
PATCH /apps/{id}
- missing app:
- creates via
POST /apps
- creates via
- if
activate=True: sets status active - if
mint_key=True: creates app key and writes.runtime-key.local - if
warm=True: invokes run endpoint withwarmup=True
- newly minted key value
- resolved runtime key fallback source
run(...)
- resolves app by owner+slug
- runtime key priority:
- explicit arg
- resolved runtime key fallback source
- calls
POST /v1/apps/{app_id}/run
events(...)
- same app and key resolution as
run(...) - optional
idempotency_keyforwarded asX-Idempotency-Key - calls
POST /v1/apps/{app_id}/events
invite(...)
- calls
POST /apps/{app_id}/invites - defaults:
role="viewer",expires_in_hours=168
setup(...)
- calls
GET /apps/{app_id}/setup
Typical return payloads
deploy(...) returns:
run(...) and events(...) return raw backend JSON response bodies unchanged.
HTTP client semantics (_Http)
Transport characteristics:
- JSON request/response
- 30s timeout per request
- control-plane auth:
Bearer <user_jwt> - runtime auth for run/events:
Bearer <runtime_key>
- Non-2xx raises
RuntimeErrorwith method/path/status/body
Internal utilities (non-exported, still relevant)
These live inmodal_like.py and shape behavior:
_slugify(value)-> workflow/agent/app id normalization_normalize_trigger(trigger, schedule)-> cron/api trigger normalization_new_run_id()-> UTC timestamp + short UUID suffix_parse_input_pairs(...)-> CLI key-value parser_read_dotenv(...)-> non-overwriting.envloader_require_env(...)-> required env var validation_task_guardrail_prefix(...)-> task instruction guardrail preamble_wrap_hook_command_with_guardrails(...)-> command workflow wrapper
CLI behavior (run_cli)
Subcommands:
deployup(alias for deploy)runeventslocalinvitesetup
- if no subcommand provided, defaults to
deploy
deploy / up
run
run_ididempotency_key(derived from workflow + run id)
events
--idempotency-key omitted, SDK generates one.
local
App object and @app.local_entrypoint().
invite
--email omitted, falls back to ARA_DEFAULT_INVITE_EMAIL.
setup
CLI input parsing rules
--input and --metadata parse only key=value pairs.
- entries without
=are ignored - key is trimmed
- empty key is ignored
Validation and error rules
Common validation errors raised by SDK:App(name=...)with empty namecron("")sandbox(policy="per_run")or any non-shared policysubagent_hook(...)with bothtaskandcommand@app.hook(...)with bothtaskandcommand@app.run(...)without command@app.run(..., agent=...)(agent not allowed in run mode)- missing runtime key for
run/events localcommand without@app.local_entrypoint()
Script runner (examples/python-sdk/ara)
./ara is a wrapper over run_cli for script-first usage:
- Loads module from script path dynamically
- Finds
appvariable or firstAppinstance in module - Supports commands:
deploy|up|run|events|setup|invite|local
Environment variables
| Variable | Required | Purpose |
|---|---|---|
ARA_ACCESS_TOKEN | yes | User JWT for /apps/* routes |
ARA_DEFAULT_INVITE_EMAIL | no | Default invite email for CLI invite |
Endpoint map used by SDK
| SDK operation | Method + path | Auth |
|---|---|---|
| List apps | GET /apps | user JWT |
| Create app | POST /apps | user JWT |
| Update app | PATCH /apps/{app_id} | user JWT |
| Get setup | GET /apps/{app_id}/setup | user JWT |
| Create key | POST /apps/{app_id}/keys | user JWT |
| Run workflow | POST /v1/apps/{app_id}/run | app runtime key |
| Send event | POST /v1/apps/{app_id}/events | app runtime key |
| Create invite | POST /apps/{app_id}/invites | user JWT |
Known current constraints
- Dedicated sandbox policies are intentionally disabled for now.
- High-scale queueing/backpressure is not built in; use your own durable queue/store.
- SDK is Python-first; JS/Go usage is not covered by this module.
Related pages
/sdk/overviewfor primitives + hello-world cron/sdk/quickstartfor end-to-end run sequence/examples/meeting-investor-botfor the investor meeting app walkthrough

