compose
Goldsky Compose
Goldsky Compose is the offchain-to-onchain framework for high-stakes systems. Write TypeScript tasks that run in verifiable sandboxes — triggered by cron, HTTP, or onchain events — with smart wallets, gas sponsorship, and durable collections. Typical use cases: custom price oracles, keepers, circuit breakers, prediction-market resolvers, cross-chain automation, identity/attestation flows, and notifications.
Boundaries
- Build new Compose apps or explain what Compose is. For debugging a broken app, use
/compose-doctor. - Do not serve as a manifest / CLI / API reference. For field syntax, flag lookups, or TaskContext shapes, use
/compose-reference. - For
goldsky login, use/auth-setup. For generic secret management, use/secrets.
Mode Detection
Before running commands, check if the Bash tool is available:
- If Bash is available (CLI mode): use the Walk Me Through It section below to execute commands directly and parse output.
- If Bash is NOT available (reference mode): the Quickstart below is enough for most chatbot Q&A. For step-by-step help, output one command at a time and ask the user to paste output back.
What Compose Does
- Serverless TypeScript runtime for EVM-aware tasks.
- Three trigger types: cron, HTTP, onchain_event.
- Smart wallets (managed by Goldsky, gas-sponsored by default) or BYO EOA wallets (user-supplied private key).
- Built-in secrets, collections (durable storage), typed contract bindings via codegen.
compose devfor hot-reload local dev;compose deployto ship;compose logs -fto tail.
Out of Scope (for this skill)
- Deploying the target onchain contract. Compose writes to contracts that already exist. If the user needs one deployed, direct them to Foundry / Hardhat first and resume here once they have the address + ABI.
- Sourcing a contract ABI. The user provides the ABI JSON file; this skill does not fetch from Etherscan / Sourcify.
- Funding a BYO EOA. If sponsorship is off, the user must fund the address out-of-band.
Quickstart
Install
curl https://goldsky.com | sh
goldsky login
Scaffold + deploy
goldsky compose init <app-name> # scaffolds a Bitcoin-oracle example
cd <app-name>
goldsky compose dev # hot-reload local server on :4000
goldsky compose deploy # bundle + upload to cloud
goldsky compose status # expect RUNNING
goldsky compose logs -f # stream logs
Minimal compose.yaml + task
# compose.yaml
name: my-oracle
api_version: stable
secrets:
- ORACLE_ADDRESS
tasks:
- name: hourly_update
path: src/tasks/hourly-update.ts
triggers:
- type: cron
expression: "0 * * * *"
// src/tasks/hourly-update.ts
import type { TaskContext } from "compose";
export async function main({ evm, env, logEvent }: TaskContext) {
const wallet = await evm.wallet({ name: "updater" });
const tx = await wallet.writeContract(
evm.chains.polygonAmoy,
env.ORACLE_ADDRESS,
"update(uint256)",
[BigInt(Date.now())],
{ confirmations: 3, onReorg: { action: { type: "replay" }, depth: 200 } },
);
await logEvent({ code: "updated", message: "ok", data: { hash: tx.hash } });
}
Core Concepts
Tasks
A task is a TypeScript file exporting async function main(context, params?). Each task declares one or more triggers in compose.yaml.
Triggers
| Type | Fires on | Key config |
|---|---|---|
cron |
schedule | expression (5-field cron) |
http |
HTTP POST to /tasks/<name> |
authentication: auth_token | none, optional ip_whitelist |
onchain_event |
decoded log | network (snake_case), contract, events (viem signature strings) |
TaskContext
Every task receives { env, fetch, callTask, logEvent, evm, collection }. Secrets flatten into context.env — there is no separate secrets namespace. See /compose-reference for the full API.
Wallets
Two kinds:
- Smart wallet (managed) —
evm.wallet({ name: "updater" }). Hosted by Goldsky, gas-sponsored by default. Cannot be used in plain local dev — usecompose dev --fork-chainsor switch to a BYO EOA. - BYO EOA (private key) —
evm.wallet({ privateKey: env.MY_KEY, sponsorGas: true }). Gas sponsorship is OFF by default for BYO EOA wallets; opt in explicitly.
Secrets & env
List names in the manifest's secrets: array, set values with goldsky compose secret set --name X --value Y (or compose secret sync to upload .env). Values flatten into context.env at runtime. Names must be SCREAMING_SNAKE_CASE.
Gas sponsorship
Bundler fallback: Alchemy → Pimlico → Gelato. Broad EVM coverage (mainnet + testnet); see /compose-reference for the chain list and caveats.
Dashboard
Every deployed app has a dashboard at https://app.goldsky.com/<project_id>/dashboard/compose/<app-name>.
Capability Tour
Inline worked examples. Start with Cron → writeContract if you don't know which applies.
Cron → writeContract (the scaffold default)
Exactly the minimal task above — a cron task that writes to a contract every hour, with onReorg: replay for safety.
HTTP task with auth_token
# compose.yaml (task entry)
- name: manual_fire
path: src/tasks/manual-fire.ts
triggers:
- type: http
authentication: auth_token
// src/tasks/manual-fire.ts
import type { TaskContext } from "compose";
export async function main({ logEvent }: TaskContext, params: { amount: number }) {
await logEvent({ code: "fired", message: "manual", data: params });
return { ok: true, received: params.amount };
}
Invoke: curl -X POST -H "Authorization: Bearer $TOKEN" -d '{"amount": 42}' https://<app-url>/tasks/manual_fire.
Onchain event listener
- name: on_transfer
path: src/tasks/on-transfer.ts
triggers:
- type: onchain_event
network: polygon_amoy
contract: "0xYourContract"
events:
- "Transfer(address,address,uint256)"
import type { TaskContext } from "compose";
export async function main(
{ evm, logEvent }: TaskContext,
params: { log: { topics: string[]; data: string; address: string } },
) {
const decoded = await evm.decodeEventLog(
[{ type: "event", name: "Transfer", inputs: [/* ABI inputs */] }],
params.log,
);
await logEvent({ code: "transfer", message: "seen", data: decoded });
}
Smart wallet + sponsored writeContract
const wallet = await evm.wallet({ name: "my-oracle" }); // sponsorGas defaults TRUE
const tx = await wallet.writeContract(
evm.chains.base,
env.FEED_ADDRESS,
"setPrice(uint256)",
[1234n],
);
BYO EOA with sponsored gas (opt-in)
const wallet = await evm.wallet({
privateKey: env.MY_KEY,
sponsorGas: true, // MUST opt in; defaults FALSE
});
Durable storage (collection)
const runs = await collection<{ id: string; ts: number }>("runs");
await runs.setById("latest", { id: "latest", ts: Date.now() });
const recent = await runs.findOne({ ts: { $gt: Date.now() - 86_400_000 } });
Typed contracts via codegen
Drop an ABI into src/contracts/Oracle.json. After goldsky compose codegen (or any init/dev/deploy), the contract is available as evm.contracts.Oracle. Full workflow in /compose-reference.
Walk Me Through It
Only activate when Bash is available.
Step 1 — Verify auth
goldsky project list 2>&1. If not logged in, use /auth-setup.
Step 2 — Derive first, ask only the ambiguous
From the user's natural-language prompt, derive as many of these as possible before asking:
- Trigger type — "every 5 minutes" → cron; "on each Transfer" → onchain_event; "when I call it" → http.
- Chain — named (
polygonAmoy,base) → use it; "testnet" with no name → ask. - Read vs write — "track", "index", "notify" → read; "update", "set", "submit" → write.
- Wallet — write + sponsored gas → smart wallet (default); user supplied a PK → BYO EOA with
sponsorGas: true. - Secrets — any external API key or contract address → needs a secret entry.
api_version— default tostableunless user asks otherwise.
Only ask the user for fields you couldn't derive.
Step 3 — Scaffold
goldsky compose init <name>. Inspect the scaffold to see the canonical file layout.
Step 4 — Edit the manifest
Replace the scaffold's task block with the derived trigger + secret list. Use the YAML snippets from the Capability Tour above.
Step 5 — Write the task
Replace the scaffold's task file with logic derived from the prompt. Use the capability-tour snippet for the chosen trigger as the starting point.
Step 6 — Wire secrets and wallets
- Every name in
compose.yaml'ssecrets:→goldsky compose secret set --name X --value Y(or add to.env+compose secret sync). - Smart wallet →
goldsky compose wallet create --name <name>. Thenwallet listto get the address and share with the user (they may need to grant it onchain permissions on the target contract). - BYO EOA → add the private key to
.env(SCREAMING_SNAKE_CASE name), reference viaenv.Xin the task.
Step 7 — Local dev
goldsky compose dev. Smart wallets require --fork-chains locally; use a BYO EOA if the user wants to test against a live testnet. For HTTP tasks: goldsky compose callTask <name> '<json>' in another terminal.
Step 8 — Deploy
goldsky compose deploy. Expect progress: "Building Dedicated app database…" → "Deploying app…" → "Provisioning infra…" (can take a minute or two on first deploy).
Step 9 — Verify
goldsky compose status --json # expect .status == "RUNNING"
goldsky compose logs -f # expect app-specific log lines
Share the dashboard URL: https://app.goldsky.com/<project_id>/dashboard/compose/<app-name>.
Important Rules
- Smart wallets don't work in plain
compose dev— use--fork-chainsor switch to a BYO EOA for local iteration. - BYO EOA gas sponsorship defaults to FALSE — opt in explicitly with
sponsorGas: true. - Cloud secrets are not synced from
.envautomatically. Runcompose secret syncorcompose deploy --sync-env. - Secret names must be SCREAMING_SNAKE_CASE.
api_versionis required for deploy. Default tostable.
Related
/compose-doctor— Diagnose and fix broken Compose apps./compose-reference— Manifest, CLI, TaskContext API, wallets, gas sponsorship, codegen./auth-setup—goldsky loginwalkthrough./secrets— Generic secret management.
More from goldsky-io/goldsky-agent
turbo-builder
Build and deploy new Goldsky Turbo pipelines from scratch. Triggers on: 'build a pipeline', 'index X on Y chain', 'set up a pipeline', 'track transfers to postgres', or any request describing data to move from a chain/contract to a destination (postgres, clickhouse, kafka, s3, webhook). Covers the full workflow: requirements → dataset selection → YAML generation → validation → deploy. Not for debugging (use /turbo-doctor) or syntax lookups (use /turbo-pipelines).
39turbo-pipelines
Turbo pipeline YAML reference and architecture guide. Covers: YAML field syntax (start_at, from, version, primary_key), source/transform/sink configuration, validation errors, resource sizing (xs–xxl), architecture decisions (dataset vs kafka, streaming vs job, fan-out vs fan-in, sink selection, pipeline splitting). Triggers on: 'what does field X do', 'what fields does a postgres sink need', 'what resource size', 'should I use kafka or dataset', 'how to structure my pipeline'. For writing transforms, use /turbo-transforms. For end-to-end building, use /turbo-builder.
39secrets
Use this skill when a user wants to store, manage, or work with Goldsky secrets — the named credential objects used by pipeline sinks. This includes: creating a new secret from a connection string or credentials, listing or inspecting existing secrets, updating or rotating credentials after a password change, and deleting secrets that are no longer needed. Trigger for any query where the user mentions 'goldsky secret', wants to securely store database credentials for a pipeline, or is working with sink authentication for PostgreSQL, Neon, Supabase, ClickHouse, Kafka, S3, Elasticsearch, DynamoDB, SQS, OpenSearch, or webhooks.
34datasets
Use this skill when the user needs to look up or verify Goldsky blockchain dataset names, chain prefixes, dataset types, or versions. Triggers on questions like 'what\\'s the dataset name for X?', 'what prefix does Goldsky use for chain Y?', 'what version should I use for Z?', or 'what datasets are available for Solana/Stellar/Arbitrum/etc?'. Also use for chain-specific dataset questions (e.g., polygon vs matic prefix, stellarnet balance datasets, solana token transfer dataset names). Do NOT trigger for questions about CLI commands, pipeline setup, or general Goldsky architecture unless the core question is about finding the right dataset name or chain prefix.
34turbo-doctor
Diagnose and fix broken Goldsky Turbo pipelines interactively. Triggers on: pipeline in error state, stuck starting, connection refused, not getting data, duplicate rows, missing fields, slow backfill, or any named pipeline misbehaving. Runs logs/status commands, identifies root cause, and offers fixes. For CLI syntax or error pattern lookup without an active problem, use /turbo-operations instead.
34turbo-transforms
Write SQL, TypeScript, and dynamic table transforms for Turbo pipelines. Covers: decoding EVM logs with _gs_log_decode, filtering/casting blockchain data, UNION ALL for combining events, TypeScript/WASM transforms (invoke function), dynamic lookup tables (dynamic_table_check), transform chaining, and Solana decoding. Triggers on: 'decode Transfer events', 'write a SQL transform', 'filter by contract', 'TypeScript transform', 'dynamic table', 'UNION ALL'. For pipeline YAML structure, use /turbo-pipelines. For end-to-end building, use /turbo-builder.
33