Configuring Secrets and API Keys in the Agent-Native Onboarding Checklist
Use registerRequiredSecret() in a Nitro plugin to automatically inject API key configuration steps into the Agent-Native sidebar checklist, which hides automatically once all required secrets are stored in the scoped database.
Agent-Native provides a built-in onboarding system that guides users through essential configuration—including LLM engines, databases, and third-party API keys—via a collapsible checklist in the agent sidebar. According to the BuilderIO/agent-native source code, templates declare required secrets programmatically, and the framework automatically generates corresponding UI steps that persist values to a secure, scoped secret store rather than plain environment variables.
How Secrets Become Onboarding Steps
The framework converts secret declarations into interactive checklist items through a three-stage pipeline involving registration, auto-injection, and UI rendering.
Registering Required Secrets
Templates declare secrets using the registerRequiredSecret() function exported from packages/core/src/secrets/register.ts. This function accepts a configuration object specifying the environment variable name, human-readable label, scope, and whether the secret is mandatory.
// packages/core/src/secrets/register.ts
export function registerRequiredSecret(secret: RegisteredSecret): void {
if (secret.required) {
import("./onboarding.js")
.then((mod) => mod.maybeRegisterSecretOnboardingStep(secret))
.catch(() => {});
}
}
When required: true is set, the function lazily imports packages/core/src/secrets/onboarding.ts to trigger automatic step generation without blocking the main thread.
Auto-Injecting Steps
The helper maybeRegisterSecretOnboardingStep() in packages/core/src/secrets/onboarding.ts creates a standardized onboarding step that appears alongside built-in steps like "Connect an AI engine." This step registers itself with the internal API routes served at /_agent-native/onboarding/*.
Rendering the Checklist
The UI consumes the checklist via GET /_agent-native/onboarding/steps (documented in packages/core/docs/content/onboarding.md). The endpoint returns steps marked with required or optional pills. When a user saves an API key, the value writes to the scoped database secret store (handled in packages/core/src/secrets/routes.ts), and the isComplete callback evaluates whether the step is satisfied. The panel auto-hides when all required steps return true.
Custom Onboarding Steps
Beyond auto-generated secret steps, templates can define fully custom onboarding workflows using registerOnboardingStep() within a Nitro plugin. This enables complex authentication flows like OAuth connections or multi-step forms.
// server/plugins/my-onboarding.ts
import { defineNitroPlugin } from "@agent-native/core/server";
import { registerOnboardingStep } from "@agent-native/core/onboarding";
import { listOAuthAccounts } from "@agent-native/core/oauth-tokens";
export default defineNitroPlugin(() => {
registerOnboardingStep({
id: "gmail",
order: 100,
title: "Connect Gmail",
description: "Grant read/send access so the agent can work with email.",
methods: [
{
id: "oauth",
kind: "link",
primary: true,
label: "Sign in with Google",
payload: { url: "/_agent-native/google/auth-url?scope=mail", external: false },
},
{
id: "delegate",
kind: "agent-task",
label: "Let the agent set it up",
badge: "beta",
payload: { prompt: "Walk me through connecting Gmail. Set env vars as needed." },
},
],
isComplete: async () => (await listOAuthAccounts("google")).length > 0,
});
});
The isComplete function determines whether the step displays as finished, while the methods array defines the available interaction patterns—either direct links, agent tasks, or form inputs.
Workspace-Aware Secret Handling
When a template requires credentials that might already exist as a workspace connection (for example, a centrally managed Slack or Gmail integration), the onboarding step can query the existing connection catalog rather than prompting for duplicate API keys.
import { listWorkspaceConnectionProviderCatalogForApp } from "@agent-native/core/workspace-connections";
isComplete: async () => {
const catalog = await listWorkspaceConnectionProviderCatalogForApp({
appId: "mail",
templateUse: "mail",
provider: "gmail",
});
const conn = catalog.providers[0];
return conn?.readiness.status === "ready" && conn.workspaceConnection.grantState === "granted"
? true
: !!process.env.GMAIL_REFRESH_TOKEN;
};
This pattern checks packages/core/src/workspace-connections logic to determine if a valid connection exists before falling back to environment variable checks.
Implementation Examples
Register a Required OpenAI API Key
Create a server plugin that registers the secret and automatically generates the onboarding step:
// src/server/plugins/secrets.ts
import { defineNitroPlugin } from "@agent-native/core/server";
import { registerRequiredSecret } from "@agent-native/core/secrets";
export default defineNitroPlugin(() => {
registerRequiredSecret({
key: "OPENAI_API_KEY",
label: "OpenAI API key",
description: "Key for OpenAI LLMs",
scope: "user",
kind: "api-key",
required: true,
});
});
Custom Step with Form Input
For secrets requiring complex input (like JSON service accounts), use a form method:
// src/server/plugins/custom-onboarding.ts
import { defineNitroPlugin } from "@agent-native/core/server";
import { registerOnboardingStep } from "@agent-native/core/onboarding";
export default defineNitroPlugin(() => {
registerOnboardingStep({
id: "firebase",
order: 50,
title: "Connect Firebase",
description: "Provide your Firebase service account JSON.",
methods: [
{
id: "form",
kind: "form",
label: "Paste JSON",
payload: {
fields: [
{ name: "FIREBASE_JSON", type: "textarea", placeholder: "{ … }" },
],
writeScope: "workspace",
},
},
],
isComplete: async () => !!process.env.FIREBASE_JSON,
});
});
Client-Side Hook for the Checklist
Access the onboarding state in React components using the client-side hooks:
import { useOnboarding, OnboardingBanner } from "@agent-native/core/client/onboarding";
function SetupPanel() {
const { steps, dismiss, reopen } = useOnboarding();
return (
<OnboardingBanner onDismiss={dismiss} />
);
}
Summary
registerRequiredSecret()inpackages/core/src/secrets/register.tsis the entry point for declaring API keys that must appear in the onboarding checklist.- Setting
required: trueautomatically triggersmaybeRegisterSecretOnboardingStep()to inject the step into the UI. - Secrets persist to a scoped database store (user, workspace, or org) rather than plaintext environment variables.
- Use
registerOnboardingStep()for non-secret configuration flows like OAuth or custom forms. - Query
listWorkspaceConnectionProviderCatalogForApp()to avoid redundant credential entry when workspace connections already exist.
Frequently Asked Questions
How do I make an API key optional in the onboarding checklist?
Set required: false (or omit the property) when calling registerRequiredSecret() in packages/core/src/secrets/register.ts. Optional secrets still appear in the onboarding UI but are marked with an optional pill and do not prevent the panel from auto-hiding.
What scopes are available for secrets in Agent-Native?
The scope parameter accepts three values: user (tied to the individual account), workspace (shared across a workspace), or org (organization-wide). The value determines which database partition stores the secret and who can access it.
How does the onboarding panel know when to hide?
The panel evaluates the isComplete callback for every required step. When all required steps return true, the UI automatically collapses. For built-in secret steps, completion is verified by checking the scoped secret store; for custom steps, you define the completion logic in the registerOnboardingStep() configuration.
Can I use workspace connections instead of manual API key entry?
Yes. In your isComplete callback, import listWorkspaceConnectionProviderCatalogForApp() from @agent-native/core/workspace-connections to check if a valid connection exists. This allows the onboarding step to mark itself complete when a central admin has already configured the integration, bypassing manual key entry for end users.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →