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
- You declare secrets in
.agentdeploy/config.json(or via dashboard) ad deployuploads the manifest alongside your bundled code- Buyers see the manifest when they deploy your agent
- Buyers provide values via the dashboard or
ad secrets set - Secrets are injected into
envat runtime by Cloudflare's Secrets API
Secrets are encrypted at rest and never exposed in logs, worker code, or API responses.
Secret fields
| Field | Required | Example | Description |
|---|---|---|---|
key | Yes | STRIPE_API_KEY | SCREAMING_SNAKE_CASE, matches env.KEY |
required | Yes | true | If false, buyer can skip it |
description | No | Stripe API key | Help 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_NAMEreferences 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.