Skip to main content

Secret Manifest

The secret manifest declares what API keys and configuration values your agent needs. Buyers see this when deploying your template, and the platform uses it to validate readiness.

SDK approach​

When using @agentdeploy/edge-sdk, secrets are declared in .agentdeploy/config.json and accessed via useSecrets():

Declaration​

// .agentdeploy/config.json
{
"secrets": [
{
"key": "STRIPE_API_KEY",
"required": true,
"description": "Stripe API key for payment processing"
},
{
"key": "SLACK_WEBHOOK_URL",
"required": false,
"description": "Optional Slack notifications webhook"
}
]
}

Access in code​

import { defineTool, useSecrets } from "@agentdeploy/edge-sdk";

interface MySecrets {
STRIPE_API_KEY: string;
SLACK_WEBHOOK_URL?: string;
}

const chargeCard = defineTool({
description: "Charge a customer's card",
inputSchema: z.object({ amount: z.number(), customerId: z.string() }),
execute: async ({ amount, customerId }, ctx) => {
// Typed access — throws descriptive error if key is missing
const secrets = useSecrets<MySecrets>(ctx.env);

const res = await fetch("https://api.stripe.com/v1/charges", {
method: "POST",
headers: { Authorization: `Bearer ${secrets.STRIPE_API_KEY}` },
body: new URLSearchParams({ amount: String(amount), customerId }),
});
return await res.json();
},
});

You can also access secrets directly via ctx.env.KEY or this.env.KEY (inside agent lifecycle methods). useSecrets() is optional — it adds typed error messages.

How it works​

  1. You declare secrets in .agentdeploy/config.json (or via dashboard)
  2. ad deploy uploads the manifest alongside your bundled code
  3. Buyers see the manifest when they deploy your agent
  4. Buyers provide values via the dashboard or ad secrets set
  5. Secrets are injected into env at runtime by Cloudflare's Secrets API

Secrets are encrypted at rest and never exposed in logs, worker code, or API responses.

Secret fields​

FieldRequiredExampleDescription
keyYesSTRIPE_API_KEYSCREAMING_SNAKE_CASE, matches env.KEY
requiredYestrueIf false, buyer can skip it
descriptionNoStripe API keyHelp text shown to buyers

Setting secrets via CLI​

# Set a single secret interactively
ad secrets set STRIPE_API_KEY

# Set a secret with value inline
ad secrets set STRIPE_API_KEY "sk_live_xxx"

# List configured secrets
ad secrets list

# Show required secrets for this deployment
ad secrets required

Setting secrets via dashboard​

Buyers configure secrets in Dashboard > Deployments > [Deployment] > Secrets. Each secret field shows:

  • The key name and description you declared
  • Whether it's required or optional
  • A masked input field

Optional secrets​

If a secret is optional, your code should handle its absence:

const sendSlackNotification = defineTool({
description: "Send a Slack notification",
inputSchema: z.object({ message: z.string() }),
execute: async ({ message }, ctx) => {
const webhookUrl = ctx.env.SLACK_WEBHOOK_URL;
if (!webhookUrl) {
// Secret not configured — skip gracefully
return { sent: false, reason: "Slack webhook not configured" };
}

await fetch(webhookUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text: message }),
});
return { sent: true };
},
});

Security​

  • Secrets are never logged. The platform redacts env.SECRET_NAME references from all telemetry.
  • Encrypted at rest. Cloudflare Workers Secrets API stores them encrypted.
  • Per-deployment isolation. Each buyer deployment gets its own secret bindings.
  • Sellers never see buyer secrets. You can see that a buyer configured your required keys, but not the values.

Auto-detection from .env.example​

If your project contains a .env.example file, the CLI can auto-generate the manifest:

# .env.example in your project
STRIPE_API_KEY=your-stripe-key
SLACK_WEBHOOK_URL=https://hooks.slack.com/...
DATABASE_URL=postgres://localhost/mydb

Run ad init and the generated .agentdeploy/config.json includes entries from .env.example.