Skip to content

contember/semeno

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

semeno 🌱

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) and scenario (a complete demo state for QA, E2E suites or AI agents, with a reset hook).
  • 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--json everywhere, self-describing seeds, plan/validate commands, and a Claude Code skill installed by semeno init that teaches agents the seed contract.

Requires Bun (the config is TypeScript, imported natively).

Quick start

bun add -d @semeno/core
bunx semeno init          # scaffolds semeno.config.ts, seeds/, .claude/skills/semeno/
bunx semeno list
bunx semeno run example-seed

The seed contract

// 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.

The config

// 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).

CLI

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.

CI

One line replaces a hand-ordered list of seed invocations:

- run: bunx semeno run all --scope edu --yes

Dependencies guarantee the order; idempotency guarantees re-runs are safe.

For AI agents

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.

Programmatic API

Everything the CLI does is exported from @semeno/core: defineConfig, defineSeed, seedHelper, planRun, executePlan, validateConfig, resolveTarget, loadConfig, …

License

MIT

About

Seed scenario manager — named, idempotent, scoped, dependency-aware database seeds with an agent-friendly CLI

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors