Seed scenario manager — named, idempotent, scoped, dependency-aware database seeds with an agent-friendly CLI.
semeno is the framework around your seeds, not your database client.
You bring the clients (any ORM, GraphQL API, plain SQL); semeno gives
every project the same vocabulary and tooling:
- Named seeds with two kinds:
foundational(reference data the app needs) andscenario(a complete demo state for QA, E2E suites or AI agents, with aresethook). - Scopes — tag seeds by business stream (
edu,crm, …) and run just one stream:semeno run all --scope edu. - Dependencies — seeds declare
dependsOn; the CLI resolves the transitive closure and runs it in topological order. CI shrinks from a hand-maintained list of invocations to one command. - Targets — named environments (local/staging/prod) with secrets resolved from env vars and typed confirmation before touching anything protected.
- Agent-friendly —
--jsoneverywhere, self-describing seeds,plan/validatecommands, and a Claude Code skill installed bysemeno initthat teaches agents the seed contract.
Requires Bun (the config is TypeScript, imported natively).
bun add -d @semeno/core
bunx semeno init # scaffolds semeno.config.ts, seeds/, .claude/skills/semeno/
bunx semeno list
bunx semeno run example-seed// seeds/approved-program.ts
import { seedHelper } from '@semeno/core'
import type { SeedContext } from '../semeno.config'
const defineSeed = seedHelper<SeedContext>()
export const approvedProgram = defineSeed({
name: 'approved-program',
kind: 'scenario',
scope: 'edu',
dependsOn: ['initial-data'],
requires: ['content', 'rpc'],
description: 'Approved education program with one open session. '
+ 'State the exact end state here — humans and agents pick seeds by this text.',
run: async ctx => { /* idempotent writes via ctx clients */ },
reset: async ctx => { /* delete own artefacts, dependency order */ },
})run must be idempotent — safe to re-run on an already-seeded database.
reset removes only this seed's artefacts. Deterministic IDs (e.g. a
5eed… UUID prefix) make both easy and the rows recognizable.
// semeno.config.ts
import { defineConfig } from '@semeno/core'
export type SeedContext = { content: MyClient; rpc: (m: string, i: unknown) => Promise<unknown> }
export default defineConfig<SeedContext>({
scopes: ['edu', 'crm'],
seeds: [initialData, approvedProgram /* … */],
targets: {
local: {
endpoints: { content: 'http://localhost:1481/content/app/live', rpc: 'http://localhost:5173/rpc' },
secrets: { token: '0000…' }, // inline only for local dev
},
staging: {
endpoints: { content: 'https://engine.staging.example.com/content/app/live', rpc: 'https://api.staging.example.com/rpc' },
secretsFromEnv: { token: 'SEED_STAGING_TOKEN' }, // env var NAME, resolved lazily
},
},
createContext: target => ({
content: new MyClient(target.endpoints.content!, target.secrets.token!),
rpc: makeRpc(target.endpoints.rpc!, target.secrets.token!),
}),
})Targets whose endpoints are not all localhost are protected by
default: run/reset print the URLs the selected seeds touch and ask
you to type the target name. --yes skips the prompt (CI).
semeno list [--scope <s>] [--json] list seeds, grouped by kind + scope
semeno info <name> [--json] description, deps, dependents
semeno plan [name…|all] [--json] execution order, nothing runs
semeno run [name…|all] [flags] apply (deps first, topological)
semeno reset <name…|all> [flags] tear down (reverse order, deps untouched)
semeno validate [--strict] [--json] cycles, unknown deps, undeclared scopes…
semeno init [--force|--skill-only] scaffold project files + agent skill
Selection: --scope <s> (shared scope-less seeds always match),
--no-deps, --reset (tear the requested seeds down before the run —
pulled-in dependencies are never reset), --dry-run.
Targets: --target <name>, --endpoint k=url, --setting k=v,
--secret k=v, --yes.
run --json streams JSONL events (seed:start, seed:done,
seed:skip, seed:error) followed by a summary document. Exit codes:
0 ok, 1 failure, 2 usage error.
One line replaces a hand-ordered list of seed invocations:
- run: bunx semeno run all --scope edu --yesDependencies guarantee the order; idempotency guarantees re-runs are safe.
semeno init installs .claude/skills/semeno/SKILL.md into the host
project — the authoring guide (contract, patterns, verification loop).
Agents orient with list --json, info <name> --json and plan --json
instead of reading seed implementations.
Everything the CLI does is exported from @semeno/core: defineConfig,
defineSeed, seedHelper, planRun, executePlan, validateConfig,
resolveTarget, loadConfig, …
MIT