Skip to content
← Public packages

@kentcdodds/skills

Store, retrieve, edit, version, and revert reusable agent skill documents via skillList then skillGet.

AGENTS.md

117 lines · 3.9 KB · Markdown

@kentcdodds/skills — agent notes

Human setup and intent live in README.md. This file is for agents: imports, smoke checks, snippets, and edge cases. No user secrets. Do not disable live webhooks or jobs (including the repo.pushed index sync).

Secrets

None. Durable state is packageStorage (SQLite). Do not require a plain Kody repo named skills for skillGet.

Import paths

ExportImport
overviewkody:@kentcdodds/skills
skill-listkody:@kentcdodds/skills/skill-list
skill-getkody:@kentcdodds/skills/skill-get
skill-savekody:@kentcdodds/skills/skill-save
skill-deletekody:@kentcdodds/skills/skill-delete
skill-historykody:@kentcdodds/skills/skill-history
skill-revertkody:@kentcdodds/skills/skill-revert
skill-search (retriever)kody:@kentcdodds/skills/skill-search
legacy-dumpkody:@kentcdodds/skills/legacy-dump
migrate-to-repokody:@kentcdodds/skills/migrate-to-repo
use-package-storagekody:@kentcdodds/skills/use-package-storage
on-repo-pushedkody:@kentcdodds/skills/on-repo-pushed

Prefer static imports from execute. Do not lead with packages.invoke. Agent flow: skillList then skillGet.

Smoke test (read-only)

import skillList from 'kody:@kentcdodds/skills/skill-list'

export default async function main() {
	return await skillList()
	// => [{ id, name, description, files, updatedAt }, ...]
}

Load one known skill (read-only):

import skillGet from 'kody:@kentcdodds/skills/skill-get'

export default async function main() {
	return await skillGet({ id: 'kent-writing-voice' })
}

Retriever soft-fail path:

import skillSearch from 'kody:@kentcdodds/skills/skill-search'

export default async function main() {
	return await skillSearch({ query: 'writing voice', limit: 5 })
	// => { results: [...] } or empty on budget miss
}

Mutations (no dryRun)

skillSave / skillDelete / skillRevert write immediately. Prefer read-only list/get for smoke. First create requires name and description:

import skillSave from 'kody:@kentcdodds/skills/skill-save'

export default async function main() {
	return await skillSave({
		id: 'temp-agent-smoke',
		path: 'SKILL.md',
		content: '# temp\n\nDelete me.',
		name: 'temp-agent-smoke',
		description: 'Temporary smoke skill — safe to delete.',
	})
}

Version recovery:

import skillHistory from 'kody:@kentcdodds/skills/skill-history'
import skillRevert from 'kody:@kentcdodds/skills/skill-revert'

export default async function main() {
	const history = await skillHistory({
		id: 'temp-agent-smoke',
		path: 'SKILL.md',
		limit: 10,
	})
	if (!history[0]) return { ok: false, reason: 'no history' }
	return await skillRevert({ versionId: history[0].versionId })
}

Edge cases

  • Durable home is packageStorage. Package workflows must not open a user plain skills repo for ordinary get/list/save.
  • Forkers start empty. ./use-package-storage copies from a leftover plain skills repo into SQLite and switches reads/writes to legacy.
  • skillList / skill-search use the skills_index projection (~250ms budget); search soft-fails to { results: [] } if storage is slow. skillGet reads live content.
  • skillSave / skillDelete update the index in the same call. If a plain skills repo still receives git pushes, repo.pushed → ./on-repo-pushed resyncs the index — do not disable that subscription.
  • Skill ids: lower-kebab-case. Prefer a SKILL.md entry file; make description complete enough to choose from skillList alone.
  • ./legacy-dump is read-only. ./migrate-to-repo syncs projections and can optionally switch reads; it never deletes legacy tables.
  • Public TS API fields are camelCase (updatedAt, versionId, …). SQLite column names stay snake_case; repo.pushed wire payloads stay snake_case.