| name | pikku-config |
| description | Use when managing secrets, environment variables, config, or OAuth2 credentials in a Pikku app. Covers wireSecret, wireVariable, wireOAuth2Credential, and typed config access. TRIGGER when: code uses wireSecret/wireVariable/wireOAuth2Credential, user asks about env vars, secrets, config, OAuth2, or "how do I access environment variables". DO NOT TRIGGER when: user asks about API versioning/breaking changes (use pikku-versioning), service factories (use pikku-services), or auth middleware (use pikku-security). |
| installGroups | ["core"] |
Pikku Config, Secrets & OAuth2
Agent Operating Procedure
Use this skill as an execution checklist, not reference material.
- Discover before editing. Prefer OpenCode tools such as
pikku-meta when available; otherwise run the relevant pikku meta ... --json command and inspect only the focused output you need.
- Identify the source files that own the behavior. Do not start by reading generated output,
.pikku, node_modules, vendored packages, or broad build artifacts.
- Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
- Validate with the narrowest relevant command first, then run
pikku-verify or pikku all when functions, wirings, schemas, or generated clients may have changed.
- If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
Manage secrets, variables, and OAuth2 credentials. Never use process.env in Pikku functions — use typed services instead.
Before You Start
pikku info functions --verbose
pikku info tags --verbose
See pikku-concepts for the core mental model.
Secrets & Variables
wireSecret(config)
Declare a secret with a Zod schema for type-safe access:
wireSecret({
name: string,
schema: ZodSchema,
})
wireVariable(config)
Declare a variable (non-sensitive config) with a Zod schema:
wireVariable({
name: string,
schema: ZodSchema,
})
Accessing in Functions
const config = await services.secrets.getSecret('SECRET_NAME')
const flags = await services.variables.getVariableJSON('VARIABLE_NAME')
const apiKey = services.variables.get('API_KEY')
Local Development Services
import { LocalSecretService, LocalVariablesService } from '@pikku/core/services'
const createSingletonServices = pikkuServices(async (config) => ({
secrets: new LocalSecretService(),
variables: new LocalVariablesService(),
}))
Usage Patterns
wireSecret({
name: 'STRIPE_CONFIG',
schema: z.object({
apiKey: z.string().startsWith('sk_'),
webhookSecret: z.string(),
}),
})
const config = await secrets.getSecret('STRIPE_CONFIG')
wireVariable({
name: 'FEATURE_FLAGS',
schema: z.object({
darkMode: z.boolean(),
maxUploadMB: z.number().default(10),
}),
})
const flags = await variables.getVariableJSON('FEATURE_FLAGS')
OAuth2 Credentials
wireOAuth2Credential(config)
wireOAuth2Credential({
name: string,
displayName: string,
secretId: string,
tokenSecretId: string,
authorizationUrl: string,
tokenUrl: string,
scopes: string[],
})
Usage
wireOAuth2Credential({
name: 'slackOAuth',
displayName: 'Slack OAuth',
secretId: 'SLACK_OAUTH_APP',
tokenSecretId: 'SLACK_OAUTH_TOKENS',
authorizationUrl: 'https://slack.com/oauth/v2/authorize',
tokenUrl: 'https://slack.com/api/oauth.v2.access',
scopes: ['chat:write', 'channels:read'],
})
const response = await slackOAuth.request(
'https://slack.com/api/chat.postMessage',
{
method: 'POST',
body: JSON.stringify({ channel, text }),
}
)
const data = await response.json()
Key Rule
Never use process.env inside Pikku functions. Use the variables or secrets service:
const apiKey = process.env.API_KEY
const apiKey = services.variables.get('API_KEY')
process.env belongs only in server bootstrap code (start.ts).
Complete Example
wireSecret({
name: 'DATABASE_CONFIG',
schema: z.object({
connectionString: z.string().url(),
maxPoolSize: z.number().default(10),
}),
})
wireVariable({
name: 'APP_CONFIG',
schema: z.object({
appName: z.string(),
maxUploadSizeMB: z.number().default(10),
maintenanceMode: z.boolean().default(false),
}),
})
wireOAuth2Credential({
name: 'githubOAuth',
displayName: 'GitHub OAuth',
secretId: 'GITHUB_OAUTH_APP',
tokenSecretId: 'GITHUB_OAUTH_TOKENS',
authorizationUrl: 'https://github.com/login/oauth/authorize',
tokenUrl: 'https://github.com/login/oauth/access_token',
scopes: ['read:user', 'repo'],
})
export const getAppStatus = pikkuSessionlessFunc({
title: 'Get App Status',
func: async ({ variables, secrets }) => {
const appConfig = await variables.getVariableJSON('APP_CONFIG')
return {
appName: appConfig.appName,
maintenanceMode: appConfig.maintenanceMode,
}
},
})